2014-01-27 10 views
5

Я работаю в среде, где разработчики используют разные IDE - Eclipse, Netbeans и IntelliJ. Я использую @Nonnull аннотацию (javax.annotation.Nonnull), чтобы указать, что метод никогда не возвращает нуль:@Nonnull с различными IDE - предупреждение о ненужных проверках нуля

@Nonnull 
public List<Bar> getBars() { 
    return bars; // this.bars is a final, initialized list 
} 

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

  1. Изменить способ вернуть нуль без удаления @Nonnull аннотации
  2. Излишне проверить нуль методов, которые явно определены с @Nonnull: если (foo.getBars() == NULL) {... что-то ...}

Первый сценарий поддерживается, например. от IntelliJ. Второе - нет; клиенты не предупреждают, что проверка на нуль не нужна.

Мы в любом случае планирования, чтобы двигаться в направлении возвращения клонов коллекций вместо самих коллекций, так что лучше забыть @Nonnull и сделать это вместо того, чтобы:

public List<Bar> getBars() { 
    return new ArrayList<Bar>(bars); 
} 

Edit:

Чтобы уточнить, я не рассматриваю возможность изменения IDE для этого. Я хотел бы знать, поддерживается ли то, что я описал выше, упомянутыми IDE - или, альтернативно, если есть веская причина, почему он не поддерживается.

Я понимаю, что не слишком полагаюсь на контракты. Однако, если я напишу getBars() со стилем в последнем абзаце (верните клон списка), то, например, IntelliJ флаги предупреждение для любого кода, который делает

if (foo.getBars() == null) { ... } 

Если вы решили следовать за это предупреждение и удалить нулевой чек, вы, кажется, в равной степени зависит от getBars() реализация не меняется. Однако в этом случае вы, кажется, зависите от деталей реализации вместо явного контракта (как в случае с @Nonnull).

Edit # 2:

Я не обеспокоен скоростью исполнения, нулевые чеки действительно очень быстро. Меня беспокоит читаемость кода. Рассмотрим следующее:

Вариант А:

if ((foo.getBars() == null || foo.getBars().size() < MAXIMUM_BARS) && 
    (baz.getFoos() == null || baz.getFoos().size() < MAXIMUM_FOOS)) { 
    // do something 
} 

Вариант B:

if (foo.getBars().size() < MAXIMUM_BARS && 
    baz.getFoos().size() < MAXIMUM_FOOS) { 
    // do something 
} 

Я думаю, что вариант B является более удобным для чтения, чем Вариант A. Поскольку код считывается чаще, чем написано, Я хотел бы обеспечить, чтобы весь код I (и другие в нашей команде) был максимально читабельным.

+0

Если вы хотите сделать 2), вы очень сильно зависите от третьей стороны, чтобы сделать то, что она обещал и не изменился. Это действительно то, что вы хотите? Хотя может быть и внутренним, я бы предпочел быть оборонительным и проверить нули, если мой код сломается, если какой-то другой код нарушит его контракт. –

+0

Я не понял актуального вопроса - что вам нужно? Я не могу себе представить, что вы хотите отойти от IntelliJ, потому что он пропускает одну возможную диагностику. Вы хотите, чтобы IntelliJ поддерживал эту диагностику? Отправьте отчет об ошибке, если хотите. То же самое касается Eclipse и Netbeans. И что это за последний абзац? – Cubic

+0

Ну, вы можете создать метод утилиты, который охватывает случай «null», и перейти 'Util.size (foo.getBars())

ответ

6

Я бы рекомендовал следующее:

  • Палка с вашими @Nonnull и @Nullable аннотаций так же, как вы делаете это уже.
  • Определите и применяйте по умолчанию. На самом деле не имеет значения, что такое по умолчанию, но оно должно быть одинаковым для всей вашей базы кода.
  • Используйте FindBugs, чтобы проверить ваши случаи 1 и 2. У FindBugs есть плагины для большинства IDE, я видел Eclipse, Netbeans и IntelliJ, но их больше. (Номер 2 корпус покрыт правилом RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE. Я проверял. Просто думал, что я должен упомянуть, что после прочтения комментария DavidHarkness' в другом месте на этой странице.)

Этот подход IDE агностик и работает также во внешнем построить такую ​​среду, как Хадсон или Дженкинс.

+0

Я чувствую, что это лучший ответ, поэтому я принимаю его. Я буду экспериментировать с FindBugs, чтобы узнать, действительно ли это предупреждение для случая 2. –

+0

Протестировано снова на работе. С помощью Maven и плагина Eclipse FindBugs генерирует предупреждение при использовании '! =' В сравнении - не при тестировании с равенством, как в OP. Я написал для него [issue] (https://sourceforge.net/p/findbugs/bugs/1248/). Использует ли 'nonNullValue == null' генерирование предупреждения для вас? –

+0

@DavidHarkness [Вот скриншот] (http://i44.tinypic.com/vsde85.gif) моего редактора Eclipse. Синим маркером ошибки является появление RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE. –

0

Я думаю, с аннотациями вы хотите сделать две вещи:

  • делают программу быстрее
  • делают программисты должны работать меньше (потому что они не должны набирать нулевые чеки)

Для первого: Null-check практически не использует ресурсы. Если вы запустите этот образец:

public static void main(String[] args) { 
    long ms = System.currentTimeMillis(); 
    for (int i=0;i<10000;i++) { 
     returnsNonNull(i); 
     doNothing(); 
    } 
    System.out.println("Without nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete"); 

    ms = System.currentTimeMillis(); 
    for (int i=10000;i<20000;i++) { 
     if (returnsNonNull(i)!=null) { 
      doNothing(); 
     } 
    } 
    System.out.println("With nullcheck took "+(System.currentTimeMillis()-ms)+" ms to complete"); 
} 

public static String returnsNonNull(int i) { 
    return "Foo "+i+" Bar"; 
} 
public static void doNothing() { 

} 

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

Теперь ко второму пункту: Вы на самом деле заставляете программистов работать больше, не меньше. За исключением случаев, когда в вашем проекте и инфраструктуре абсолютно нет функций, которые когда-либо возвращают null, программист должен каждый раз искать функцию, чтобы проверить, должен ли он выполнять нуль-чек или нет. Увидев, что о каждой структуре Java может при некоторых условиях возвращать null в некоторых функциях, вы не уменьшаете рабочую нагрузку для своих программистов.

Вы сказали, что хотите, чтобы появилось предупреждение, когда они выполняют нулевую проверку, где это не необходимо из-за вашей аннотации @ Nonnull. Итак, что они будут делать, они набирают всю нулевую проверку, а затем получают предупреждение и вынуждены удалять ее снова. Смотрите, что я имею в виду?

Также, если вы допустили ошибку в своем коде и отметили что-то как @Nonnull, которое может вернуть значение null?

Что бы я сделал, это записать его в Javadoc под названием @ return. Затем программист может решить, что он делает, что обычно лучше, чем заставить других писать код вашего стиля.

+2

Мы используем аннотации на уровне пакета, чтобы пометить * каждый * метод возвращаемое значение, параметр и поле как '@ Nonnull' по умолчанию, потому что много кода проще рассуждать без нулей. Программисты должны переопределить его на уровне элемента, если они не могут уйти, не используя 'null'. В сочетании с модульными тестами и FindBugs это спасло бесчисленные головные боли за последний год. –

+2

Кроме того, остерегайтесь микро-тестов: JVM и JIT могут играть с байт-кодом, и вы никогда не знаете, что еще занимает циклы процессора. –

+1

Всегда лучше иметь более подробную информацию в контракте. Нечеткие контракты никогда не бывают хорошими. –

2

Одна вещь, которую нужно добавить к принятому ответу - если вы используете аннотации из jsr305 - используйте @CheckForNull вместо @Nullable. Подробнее об этом здесь: https://today.java.net/pub/a/today/2008/09/11/jsr-305-annotations.html В двух словах - намерение @Nullable - просто сказать, что нуль в порядке, и никаких дополнительных проверок не требуется. @CheckForNull говорит, что каждое использование отмеченного поля должно быть проверено на значение null и будет сообщаться с помощью findbugs (как и избыточная проверка нулевого значения и присвоение этого значения одному помеченному как @Nonnull).

P.S.Извините, это должен был комментарий, а не ответ, но у меня все еще недостаточно репутации, чтобы комментировать ...