HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: java, java developer, программирование на java, разработка на java, null-монада</p>
1 <p>Теги: java, java developer, программирование на java, разработка на java, null-монада</p>
2 <p>В программировании часто возникает задача вернуть из функции какое-нибудь значение. Причём это значение может быть, а может и не быть. Например, функция обращается к таблице базы данных и выбирает некоторое значение по ключу. Это значение может найтись, а может и не найтись.</p>
2 <p>В программировании часто возникает задача вернуть из функции какое-нибудь значение. Причём это значение может быть, а может и не быть. Например, функция обращается к таблице базы данных и выбирает некоторое значение по ключу. Это значение может найтись, а может и не найтись.</p>
3 <p>Что делать со значением понятно - его надо просто вернуть. А что делать, если значения в таблице нет?</p>
3 <p>Что делать со значением понятно - его надо просто вернуть. А что делать, если значения в таблице нет?</p>
4 <h2>Рассмотрим варианты действий</h2>
4 <h2>Рассмотрим варианты действий</h2>
5 <p>Итак, у нас есть несколько вариантов:</p>
5 <p>Итак, у нас есть несколько вариантов:</p>
6 <p>Можно устанавливать специальный код ошибки, а потом его проверять. Такой подход широко практиковался в языке Си. Понятно, что сейчас это выглядит более чем странно.</p>
6 <p>Можно устанавливать специальный код ошибки, а потом его проверять. Такой подход широко практиковался в языке Си. Понятно, что сейчас это выглядит более чем странно.</p>
7 <p>Другой вариант - выбрасывать исключение типа VALUE_NOT_FOUND. Вариант популярный, но тоже с кучей недостатков. Начнём с типа исключения. Оно должно быть<strong>checked</strong>? Тогда его надо будет декларировать и дальше за собой таскать, сейчас это как минимум не модно. Если<strong>Unchecked</strong>, то как сообщить клиентскому коду, что может быть такие исключение и это фактически часть бизнес-логики?</p>
7 <p>Другой вариант - выбрасывать исключение типа VALUE_NOT_FOUND. Вариант популярный, но тоже с кучей недостатков. Начнём с типа исключения. Оно должно быть<strong>checked</strong>? Тогда его надо будет декларировать и дальше за собой таскать, сейчас это как минимум не модно. Если<strong>Unchecked</strong>, то как сообщить клиентскому коду, что может быть такие исключение и это фактически часть бизнес-логики?</p>
8 <p>Реализовывать бизнес-логику на исключениях тоже вариант ниже среднего. Поэтому, часто в таких случаях, если значение не найдено, возвращают просто<strong>null</strong>. Казалось бы, это годное решение. Однако работа с<strong>null-ами</strong>- так себе удовольствие. Надо постоянно думать про NullPointerException. Все решения какие-то несуразные.</p>
8 <p>Реализовывать бизнес-логику на исключениях тоже вариант ниже среднего. Поэтому, часто в таких случаях, если значение не найдено, возвращают просто<strong>null</strong>. Казалось бы, это годное решение. Однако работа с<strong>null-ами</strong>- так себе удовольствие. Надо постоянно думать про NullPointerException. Все решения какие-то несуразные.</p>
9 <h2>Какие есть ещё варианты?</h2>
9 <h2>Какие есть ещё варианты?</h2>
10 <p>В ряде языков программирования эта проблема решается при помощи так называемой<strong>Null-монады</strong>. Есть такая возможность и в<strong>java</strong>. Давайте с ней познакомимся.</p>
10 <p>В ряде языков программирования эта проблема решается при помощи так называемой<strong>Null-монады</strong>. Есть такая возможность и в<strong>java</strong>. Давайте с ней познакомимся.</p>
11 <p>Допустим, у нас есть функция, которая может возвращать или строку или<strong>Null</strong>:</p>
11 <p>Допустим, у нас есть функция, которая может возвращать или строку или<strong>Null</strong>:</p>
12 public String mayBeNull() { //return "test"; return null; }<p>Раскомментируйте нужную строку, чтобы получить нужный вариант.</p>
12 public String mayBeNull() { //return "test"; return null; }<p>Раскомментируйте нужную строку, чтобы получить нужный вариант.</p>
13 <h2>Как может выглядеть код, в котором будет использоваться эта функция?</h2>
13 <h2>Как может выглядеть код, в котором будет использоваться эта функция?</h2>
14 <p>Примерно так:</p>
14 <p>Примерно так:</p>
15 public void useMayBeNull() { String value = mayBeNull(); if (value == null) { System.out.println("action with null"); } else { System.out.println("action with NOT null: " + value); } }<p>В принципе, получился нормальный, рабочий вариант, который часто встречается на практике. Выглядит он громоздко, некрасиво. Более того, если вместо System.out.println мы захотим передавать значение в другие функции, то нам надо будет всегда помнить про возможность null, т. е. всегда делать проверку типа if (value == null), это очень неудобно и легко забыть.</p>
15 public void useMayBeNull() { String value = mayBeNull(); if (value == null) { System.out.println("action with null"); } else { System.out.println("action with NOT null: " + value); } }<p>В принципе, получился нормальный, рабочий вариант, который часто встречается на практике. Выглядит он громоздко, некрасиво. Более того, если вместо System.out.println мы захотим передавать значение в другие функции, то нам надо будет всегда помнить про возможность null, т. е. всегда делать проверку типа if (value == null), это очень неудобно и легко забыть.</p>
16 <p>Давайте перепишем этот пример с использованием<strong>null-монады</strong>. В java эта концепция реализуется через класс<strong>Optional</strong>.</p>
16 <p>Давайте перепишем этот пример с использованием<strong>null-монады</strong>. В java эта концепция реализуется через класс<strong>Optional</strong>.</p>
17 public Optional&lt;String&gt; mayBeNullOptional() { return Optional.ofNullable("test"); //return Optional.ofNullable(null); //return Optional.empty(); }<p>И как с этим работать:</p>
17 public Optional&lt;String&gt; mayBeNullOptional() { return Optional.ofNullable("test"); //return Optional.ofNullable(null); //return Optional.empty(); }<p>И как с этим работать:</p>
18 public void useMayBeNullOptional() { Optional&lt;String&gt; value = mayBeNullOptional(); System.out.println( value.map(val -&gt; "action with NOT null:" + val) .orElse("action with null")); }<p>Обратите внимание, что в этом случае у нас нет<strong>if-условия</strong>. Т. е. у нас нет шанса забыть про обработку значений и неожиданно получить<strong>NPE-исключение</strong>. Да и сама запись получилась более компактная, красивая и современная.</p>
18 public void useMayBeNullOptional() { Optional&lt;String&gt; value = mayBeNullOptional(); System.out.println( value.map(val -&gt; "action with NOT null:" + val) .orElse("action with null")); }<p>Обратите внимание, что в этом случае у нас нет<strong>if-условия</strong>. Т. е. у нас нет шанса забыть про обработку значений и неожиданно получить<strong>NPE-исключение</strong>. Да и сама запись получилась более компактная, красивая и современная.</p>
19 <p><em>В<a>следующей части</a>мы посмотрим на некоторые моменты использования<strong>Optional</strong>!</em></p>
19 <p><em>В<a>следующей части</a>мы посмотрим на некоторые моменты использования<strong>Optional</strong>!</em></p>
20  
20