Как стать автором
Обновить

Комментарии 26

Проблема для C# актуальна, решается точно так же — аннотациями и статическим анализом (причем в том числе и на основе аннотаций JetBrains).
Спасибо.
Жаль лишь, что, в отличие от Eclipse, аннотации на пакет целиком (как @NonNullByDefault или @ParametersAreNonnullByDefault) не поддерживаются.
вы уверены? была же доработка и выглядит это теперь так:
с аннотацией @ParametersAreNonnullByDefault
с аннотацией @ParametersAreNullableByDefault
Спасибо, поправил.
Более того, функциональность, по-видимому, присутствует и в IDEA 13.1.6 (сборка 135.1306)

если я правильно понял, функциональность эта со сборки 134.738
Optional/scala Option задают контракт более явно.
И не надо никаких обходных маневров. :)
Да, ладно… Что мешает в метод, принимающий Optional, передать null вместо экземпляра объекта?
Ревью
Option защищает от случайных ошибок, а не от целенаправленного головотяпства разработчика, что вполне достаточно. А так да, запретить null вообще было бы более сильным решением, но из-за совместимости с Java приходится это терпеть.
Option в Scala позволяет коду не падать в таких случаях, но и код корректно не будет работать. По своему опыту скажу, что это намного хуже для поиска ошибки.
Как правильно сказано в первом комментарии, главное — этот как раз контракт. Если значения может не быть — делаешь Option. Если видишь Option — готовься к тому, что значения может не быть.

Падать или не падать — вопрос второстепенный. Можно без Option явно проверять все аргументы на null и не падать. Можно наоборот не глядя делать Option.get и падать.
>Падать или не падать — вопрос второстепенный.

Вообще-то тут достаточно однозначно, в случае получения как аргумента Option падать нельзя, его нужно обрабатывать. Если нужно падать в случае отсутвия значения, то нужно в момент получения сделать .get, и дальше этот Option не пускать.
Видимо вы столкнулись с неправильным применением Option. Ведь и null ссылки зачастую обрабатываются неверно, тупо все проверяется на null, и в случае null ничего не делается, таким образом происходит проглатывание ошибок.
НЛО прилетело и опубликовало эту надпись здесь
Так далеко ходить не нужно :) Есть c#, kotlin, swift, rust
НЛО прилетело и опубликовало эту надпись здесь
У нас тоже аннотации используются — отличная вещь, позволила найти/не допустить несколько ошибок. Плюс это такой зачаток программирования по контракту — когда определяешь метод сразу же аннотируешь возвращаемое значение и входные параметры. И потом проще его писать — не думаешь о том — будет тут null или нет, т.к. всё указано аннотациями плюс IDE проверяет. Ну и использовать этот метод проще — всё помечено аннотациями. Даже бывало укажешь аннотации для метода, а потом смотришь его использование, а там IDE показывает не нужный код — фактически метод возвращает не null, а в местах использования метода проверялось на null и этот код можно сразу удалить :)

Ещё пару замечаний по этим аннотациям и IDEA — у нас на разных проектах разные аннотации использовались в качестве NotNull И Nullable и получается, как только импортируешь проект, нужно не забыть указать эти аннотации в IDEA в качестве аннотаций NotNull и Nullable. Что хоть и не долго но не приятно и иногда забываешь. В общем, для проекта с gradle я сделал такую штуку:

/*
Установить настройки проекта для IDEA. Используется отдельная задача, т.к. задача idea в gradle не поддерживает настройки
проекта, который оформлен в виде директорий (так с 14 IDEA работает). Поэтому нужно править xml файл настроек проекта
отдельно. 
 */
task setupProject << {
    //xml файл настроек IDEA
    File miscXmlFile = new File("./.idea/misc.xml")
    // Если файла нет, то выходим. Нужно, чтобы не было ошибок в Jenkins, когда не создаются IDEA конфигурации.
    if (!miscXmlFile.exists()) {
        return;
    }
    XmlParser xmlParser = new XmlParser()
    Node miscXml = xmlParser.parse(miscXmlFile)
    // Указываем настройки NotNull и Nullable аннотаций для проекта.
    Node nullableNotNullManagerNode = miscXml.component.find { it.@name == "NullableNotNullManager" } as Node
    if (nullableNotNullManagerNode) {
        miscXml.remove(nullableNotNullManagerNode)
    }
    miscXml.append(xmlParser.parseText('''    
        <component name="NullableNotNullManager"> 
          <option name="myDefaultNullable" value="com.my_company.npe.Nullable"/>
          <option name="myDefaultNotNull" value="com.my_company.npe.NotNull"/>
          <option name="myNullables">
            <value>
              <list size="5">
                <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable"/>
                <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable"/>
                <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable"/>
                <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable"/>
                <item index="4" class="java.lang.String" itemvalue="com.my_company.npe.Nullable"/>
              </list>
            </value>
          </option>
          <option name="myNotNulls">
            <value>
              <list size="5">
                <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull"/>
                <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull"/>
                <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull"/>
                <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull"/>
                <item index="4" class="java.lang.String" itemvalue="com.my_company.npe.NotNull"/>
              </list>
            </value>
          </option>
        </component>'''

    ))
    XmlNodePrinter nodePrinter = new XmlNodePrinter(new PrintWriter(new FileWriter(miscXmlFile)));
    nodePrinter.preserveWhitespace = true
    nodePrinter.print(miscXml)
}


Эта задача позволяет автоматически указывать свои аннотации для проекта. Можно добавить её в задачу «idea», чтобы эти аннотации автоматически конфигурировались при загрузки проекта в IDEA. Пока так не стал делать, т.к. тестировал. При выполнении задачи переоткрывать проект не нужно — IDEA сама подхватит изменения. Плюс я тут вручную xml правлю, т.к. у меня не получить на таком низком уровне работать с конфигами IDEA в gradle.
Кстати, вопрос немного в сторону — я только что узнал про type annotations, которые упоминались в статье ( docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html ) Судя по докам, эти аннотации позволяют проще писать nullable анализ. Правильно? Ну, в смысле, одно из возможностей их использования.
И вообще, кто нибудь работал с ними?
При работе с Java 1.8+ авторы JDT рекомендуют использовать для null-анализа именно type annotations, см. Using null type annotations. См. тж. обсуждение bug 392099.
Аннотации FindBugs не соответствуют этому требованию

А патчик можете написать, чтобы поправить это? Если напишете, закиньте нам в багтрекер. Глядишь, успеем в 3.0.1 протолкнуть.
А, или это чисто эклипсовский баг, а не наш?
Нет, увы.

Насколько я понимаю предметную область, это проблема именно FindBugs,
но Eclipse 4.5+ уже умеет её обходить.

Я постараюсь в ближаёшее время адаптировать аннотации и сообщить Вам.

P. S. Спасибо за отклик =)
Вам спасибо за статью. К сожалению, поздно увидел.

Насчёт проблемы с полем в Eclipse — проще сразу закинуть поле в локальную переменную, тогда не придётся SuppressWarnings писать:

void doSmth() {
  Object field = this.field;
  if(field == null) {
    return;
  }
  System.out.println(field.hashCode());
}


В таком виде Eclipse ругаться не будет. Тут железобетонно не возникнет проблем даже в условиях высокой конкурентности и при выполнении интерпретируемого фрейма (понятно, что JIT-компилятор сделает то же самое — прочитает поле из кучи только один раз). Ну а ещё проще игнорировать варнинг от эклипса и использовать FindBugs, там null-анализ гораздо мощнее :-)

Насчёт CheckForNull — нам уже написали. К сожалению, это не моя зона ответственности и высоки шансы, что Билл отклонит это. Я в своих проектах сделал так, как по ссылке — сказал эклипсу считать CheckForNull за Nullable и Nullable не использую вообще.
Буквально сегодня закрыли IDEA-76782: Add compiler support for JSR-305 @Nonnull assertions — теперь еще IDEA сможет вставлять в код NotNull assertions, если включена соответсвующая опция для компилятора, учитывая выбранную конфигурацию, а не только jetbrains NotNull
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации