Каков хороший вариант использования для статического импорта методов? - PullRequest
124 голосов
/ 07 января 2009

Только что получил комментарий, что мой статический импорт метода не был хорошей идеей. Статический импорт был методом из класса DA, который имеет в основном статические методы. Итак, в середине бизнес-логики у меня была активность da, которая, казалось, принадлежала текущему классу:

import static some.package.DA.*;
class BusinessObject {
  void someMethod() {
    ....
    save(this);
  }
} 

Рецензент не был заинтересован в том, чтобы я изменил код, и я не сделал этого, но я вроде согласен с ним. Одна из причин, по которой не был выполнен статический импорт, заключалась в том, что метод определения путаницы был запутанным, его не было в текущем классе и не было в каком-либо суперклассе, поэтому слишком долго нужно было определить его определение (система просмотра через Интернет не имеет кликабельности). ссылки вроде IDE :-) Я не думаю, что это имеет значение, статический импорт все еще довольно новый, и скоро мы все привыкнем их искать.

Но другая причина, с которой я согласен, заключается в том, что неквалифицированный вызов метода, кажется, принадлежит текущему объекту и не должен переходить из контекстов. Но если он действительно принадлежит, имеет смысл расширить этот суперкласс.

Итак, когда имеет смысл для статических методов импорта? Когда ты это сделал? Вам понравилось, как выглядят неквалифицированные звонки?

РЕДАКТИРОВАТЬ: популярное мнение, кажется, что методы статического импорта, если никто не собирается путать их как методы текущего класса. Например, методы из java.lang.Math и java.awt.Color. Но если abs и getAlpha не являются неоднозначными, я не понимаю, почему readEmployee. Как и во многих вариантах программирования, я думаю, что это тоже личное предпочтение.

Спасибо за ваш ответ, ребята, я закрываю вопрос.

Ответы [ 16 ]

134 голосов
/ 07 января 2009

Это из руководства Sun, когда они выпустили эту функцию (выделено в оригинале):

Так, когда вы должны использовать статический импорт? Очень экономно! Используйте его только тогда, когда у вас возникнет искушение объявить локальные копии констант или злоупотребить наследованием (Антипаттерн Constant Interface). ... Если вы чрезмерно используете функцию статического импорта, она может сделать вашу программу нечитаемой и не поддерживаемой, загрязняя ее пространство имен всеми импортируемыми вами статическими элементами. Читатели вашего кода (включая вас через несколько месяцев после того, как вы его написали) не будут знать, из какого класса происходит статический член. Импорт всех статических членов из класса может быть особенно вредным для читабельности; если вам нужен только один или два участника, импортируйте их по отдельности.

(https://docs.oracle.com/javase/8/docs/technotes/guides/language/static-import.html)

Есть две части, которые я хочу назвать конкретно:

  • Использовать статический импорт только , когда вы испытывали искушение «злоупотребить наследованием». В этом случае, вы бы испытали желание иметь BusinessObject extend some.package.DA? Если так, статический импорт может быть более чистым способом справиться с этим. Если вы никогда не мечтали о расширении some.package.DA, то это, вероятно, плохое использование статического импорта. Не используйте его только для сохранения нескольких символов при наборе.
  • Импорт отдельных элементов. Скажите import static some.package.DA.save вместо DA.*. Это значительно облегчит поиск источника импортированного метода.

Лично я использовал эту языковую функцию очень редко, и почти всегда только с константами или перечислениями, никогда с методами. Для меня компромисс почти никогда не стоит.

60 голосов
/ 07 января 2009

Другое разумное использование для статического импорта - JUnit 4. В более ранних версиях JUnit-методы, такие как assertEquals и fail, были унаследованы, так как тестовый класс расширен junit.framework.TestCase.

// old way
import junit.framework.TestCase;

public class MyTestClass extends TestCase {
    public void myMethodTest() {
        assertEquals("foo", "bar");
    }
}

В JUnit 4 тестовым классам больше не нужно расширять TestCase, и вместо этого они могут использовать аннотации. Затем вы можете статически импортировать методы assert из org.junit.Assert:

// new way
import static org.junit.Assert.assertEquals;

public class MyTestClass {
    @Test public void myMethodTest() {
        assertEquals("foo", "bar");
        // instead of
        Assert.assertEquals("foo", "bar");
    }
}

JUnit документы , использующие его таким образом.

25 голосов
/ 07 января 2009

Effective Java, Second Edition , в конце Item 19 отмечает, что вы можете использовать статический импорт, если вы обнаружите, что сильно , используя константы из утилиты учебный класс. Я думаю, что этот принцип применим к статическому импорту как констант, так и методов.

import static com.example.UtilityClassWithFrequentlyUsedMethods.myMethod;

public class MyClass {
    public void doSomething() {
        int foo= UtilityClassWithFrequentlyUsedMethods.myMethod();
        // can be written less verbosely as
        int bar = myMethod();
    }
}

Это имеет свои преимущества и недостатки. Это делает код немного более читаемым за счет потери некоторой непосредственной информации о том, где определен метод. Тем не менее, хорошая IDE позволит вам перейти к определению, так что это не большая проблема.

Вы все равно должны использовать это экономно, и только если вы обнаружите, что используете вещи из импортированного файла много, много раз.

Редактировать: Обновлен, чтобы быть более специфичным для методов, так как это то, что относится к этому вопросу. Принцип применяется независимо от того, что импортируется (константы или методы).

11 голосов
/ 07 января 2009

Я согласен, что они могут быть проблематичными с точки зрения читабельности и должны использоваться с осторожностью. Но при использовании обычного статического метода они действительно могут улучшить читаемость. Например, в тестовом классе JUnit такие методы, как assertEquals, очевидны по своему происхождению. Аналогично для методов из java.lang.Math.

10 голосов
/ 07 января 2009

Я использую его для цвета много.

static import java.awt.Color.*;

Маловероятно, что цвета будут перепутаны с чем-то еще.

6 голосов
/ 01 марта 2018

Я думаю, что статический импорт действительно полезен для удаления избыточных имен классов при использовании таких утилит, как Arrays и Assertions.

Не знаю, почему, но Росс пропустил последнее предложение, которое упоминает об этом, в документации , на которую он ссылается .

При правильном использовании статический импорт может сделать вашу программу более читабельной, удалив шаблон повторения имен классов.

В основном скопировано из этого блога: https://medium.com/alphadev-thoughts/static-imports-are-great-but-underused-e805ba9b279f

Так, например:

Утверждения в тестах

Это наиболее очевидный случай, с которым, я думаю, мы все согласны

Assertions.assertThat(1).isEqualTo(2);

// Use static import instead
assertThat(1).isEqualTo(2);

Утилиты и перечисления

Имя класса может быть удалено во многих случаях при использовании утилитных классов, облегчающих чтение кода

List<Integer> numbers = Arrays.asList(1, 2, 3);

// asList method name is enough information
List<Integer> numbers = asList(1, 2, 3);

В пакете java.time есть несколько случаев, когда его следует использовать

// Get next Friday from now, quite annoying to read
LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.FRIDAY));

// More concise and easier to read
LocalDate.now().with(next(FRIDAY));

Пример, когда не использовать

// Ok this is an Optional
Optional.of("hello world");

// I have no idea what this is 
of("hello world");
2 голосов
/ 20 марта 2016

Я рекомендую использовать статический импорт при использовании OpenGL с Java, что является случаем использования, попадающим в "интенсивное использование констант из служебного класса" категория

Считайте, что

import static android.opengl.GLES20.*;

позволяет вам портировать оригинальный код C и написать что-то читаемое, например:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(samplerUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuffer);
glVertexAttribPointer(vtxAttrib, 3, GL_FLOAT, false, 0, 0);

вместо этого распространенного уродства:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(samplerUniform, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vtxBuffer);
GLES20.glVertexAttribPointer(vtxAttrib, 3, GLES20.GL_FLOAT, false, 0, 0);
2 голосов
/ 30 октября 2014

Я использую «import static java.lang.Math. *» При переносе тяжелого математического кода из C / C ++ в java. Математические методы отображают от 1 до 1, что упрощает преобразование перенесенного кода без указания имени класса.

2 голосов
/ 07 января 2009

Статический импорт - единственная «новая» функция Java, которую я никогда не использовал и не собираюсь использовать из-за проблем, которые вы только что упомянули.

1 голос
/ 09 ноября 2018

Мне показалось, что это очень удобно при использовании классов Utility.

Например, вместо использования: if(CollectionUtils.isNotEmpty(col))

Я могу вместо:

import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
if(isNotEmpty(col))

Какой ИМО повышает читабельность кода, когда я многократно использую эту утилиту в своем коде.

...