После статьи прошлой недели «Необязательно в коллекциях» сегодня я не могу не говорить немного больше о том же чудовище. Немного подробнее.
Класс Optionial, первоначально представленный Google Guava и позже включенный в пакет Java 8, является просто оболочкой, которая оборачивает необязательный объект. Обернутый объект является необязательным в том смысле, что он либо есть, либо в нем нет объекта, и в этом случае он пуст. Там не так много магии. Оберточный код класса Optional настаивает на том, что обернутый объект не является нулевым . В конце концов, ноль — это ноль, а не объект. Объект никогда не бывает нулевым . Только ссылка на объект может быть нулевой .
Это нюансы, мелкие детали; но важны мелкие детали. В конце концов, эти мелкие детали — это те, которые требовали введения Optional . Средний Java-кодер не видит важности таких крошечных деталей. Они думают, что Optional так же хорош, как и переменная для самого обернутого объекта, предполагая, что переменная также может быть нулевой . На каком-то уровне они правы. На своем уровне.
Этот уровень говорит о том, что хороший код работает, его можно понять и все. Большая часть корпоративного унаследованного кода, управляющего банками, страховыми компаниями, разработчиками ритмов и оружием, была создана на этом уровне. Вы не можете с этим поделать, просто надеетесь, что вам повезет, и программная ошибка не выберет ваш дом, банковский счет или тело (в случае медицинского устройства) в результате взрыва бомбы. Что вы можете сделать, так это понять проблему и внести свой вклад в постепенное улучшение ситуации. Это займет несколько поколений, если мы все не стерты с лица земли до этого.
«Код работает» и «возможно понять» — это самое основное требование к программному обеспечению. Некоторое время назад мы говорили, что если программное обеспечение работает, то это было бы нормально, и для обслуживания было достаточно, если бы было два «человека», которые могли понять код: кодер, который его создал, и Бог, который создал кодер. К счастью, есть и уровни выше. (Я имею в виду выше кодера. Не выше Бога.)
«Код работает» и «легко (не так сложно) понять» — это следующий уровень. Это важно в случае, если вам необходимо отладить код и определить причину некоторой неисправности. «Код работает» и «легко изменить» снова являются новыми шагами вверх по лестнице. Я видел код, который мог легко понять. Код был запущен. Но зависимости между различными модулями были такими сложными, как макраме или традиционный итальянский спагетти. Где бы я ни хотел что-то изменить, чтобы исправить ошибку здесь, было несколько других мест, где программа начала давать сбой. Легко изменить: такого кода не было.
Следующий уровень — «работа с кодом», «легко модифицировать» и «сложно создавать плохие модификации». Это означает, что код обеспечивает стиль и внутренние структуры данных и API, которым обслуживающий персонал будет следовать до определенного уровня, и создаст работающий модифицированный код, который все еще работает, прост для понимания и изменения. Это точка, где мы дошли до точки Факультативного .
Когда метод возвращает Optional, он говорит, что он может вернуть что-то или просто ничего. Необязательный <Integer> может вернуть Integer, но он может просто вернуть пустой Optional , что означает: не было никакого Integer, которое я мог бы вернуть. Почему это лучше, чем возвращать целое число, которое может быть нулевым ?
Необязательный метод, возвращающий значение
Ответ заключается в том, что в случае возврата необязательного <Integer> вы не можете:
1
2
|
integer = methodReturningIntegerOrNull(); otherInteger = integer + 1 ; |
что вызывает NPE. Почему ты так поступил? Потому что вы забыли проверить, и JavaDoc упоминает о возможности где-то в конце описания, которая не отображается в окне мыши при кодировании. В случае необязательного <Integer> вы вынуждены:
1
2
3
4
|
optionalInteger = methodReturningOptionalInteger(); if ( optionalInteger.isPresent() ){ otherInteger = optionalInteger.get() + 1 ; } |
Тем не менее, есть небольшой шанс, что вы напишите:
1
2
|
optionalInteger = methodReturningOptionalInteger(); otherInteger = optionalInteger.get() + 1 ; |
но в этом случае вы заслуживаете того, что получаете.
Необязательно поможет вам создать больше кода и меньше документации. Это дает семантику для передачи некоторого необязательного значения способом, которым труднее пренебречь, чем значением NULL. Он говорит: я не верю, что вы обрабатываете null должным образом, поэтому я даю вам обернутый объект, поэтому вы должны явно обрабатывать опциональность.
Если вы считаете, что вы можете легко ответить на вопросы
- требующий Необязательный <Something> в качестве аргумента метода
- наличие частного поля необязательно.
хорошие идеи.
Необязательный аргумент метода
Есть плюсы и минусы. Когда аргумент говорит:
1
|
countFrom(Optional<Date> from, Date to); |
ясно, что значение from может отсутствовать, и при передаче отсутствующего значения должна быть определенная семантика по умолчанию. С другой стороны, вызывающая сторона может передать значение null, чтобы получить особое поведение. Менее вероятно, что вызывающий абонент обнулится просто по ошибке, пренебрегая дополнительностью. Даже если аргумент является Необязательным, фактически переданный аргумент может быть нулевым, и я ожидаю, что в этом случае метод выдает NPE. Наконец, что не менее важно, существует еще одна опасность, представляющая Optional : вызывающий может передать Optional, охватывающий объект, который не является Date . Обобщения могут быть легко обойдены в Java, а неаккуратный кодер может передать неправильный необязательный параметр . Это означает, что вы должны реализовать утверждения в своем методе:
- аргумент не нулевой,
- Аргумент имеет правильный тип.
Также напомним, что Optional , в случае, если возвращаемое значение метода говорит: я не доверяю вам, если вы обрабатываете null должным образом, поэтому я даю вам упакованный объект, поэтому вы должны явно обработать опциональность . Что бы это сообщение было, когда вы создаете API, требующий в качестве аргумента Optional ? Пожалуйста, не верьте мне! Дайте мне только Необязательный, потому что даже я не доверяю себе правильно обрабатывать нулевое значение. Странно … С другой стороны, я верю, что вы не передадите нулевой или неправильный тип.
На мой взгляд: в этом случае использование Optional не приносит большей пользы, чем наличие надлежащей документации для API, и не заставляет вызывающую сторону вести себя лучше, чем в любом случае. С другой стороны вы кладете дополнительный код на свое плечо.
Дайте необязательно код, которому вы доверяете, примите его из кода, который не доверяет вашему коду, но не запрашивает его! Доверяй себе!
Частные дополнительные поля
Когда вы объявляете локальное, закрытое поле необязательным, вы заставляете разработчика самого класса уделять больше внимания дополнительной функции поля. Стоимость этого — дополнительная обертка, дополнительный беспорядок в обработке кода, необязательный. С другой стороны, особого выигрыша нет, потому что вы можете получить тот же уровень качества, расширяя свои модульные тесты, проверяя все случаи, когда следует учитывать нулевое значение поля. Поскольку весь код находится в руках текущего разработчика, отвечающего за весь код, преимущества Optional отсутствуют . Это снова, как ты не доверяешь себе. Это серьезная проблема, требующая большего и другого подхода, чем то, что может обеспечить класс Optional Java.
Опционально в функциональном программировании
Вы можете использовать Optional для программирования Java в стиле функционального программирования, если хотите, но Java не является функциональным языком и необязательным, и лямбда и только методы функционального стиля этого не сделают. Но это другая тема для дальнейшего.
Ссылка: | Необязательное использование необязательно от нашего партнера JCG Питера Верхаса из блога Java Deep . |