Учиться никогда не поздно, особенно для вкусностей в Java 8. Optional — одно из них, которое предоставляет решение на уровне класса для представления необязательных значений вместо нулевых ссылок. Как Java-программист, я действительно сыт по горло NullPointerException (NPE), хотя я знаю его как старого друга и знаю, что это последнее средство — программа использует объект и обнаруживает, что значение объекта равно null , поэтому виртуальная машина Java сердито выбросила его как козла отпущения.
Конечно, мы, программисты, несем ответственность и не сидим сложа руки, поэтому проверок на null много. Хотя бывают случаи, когда такие проверки совершенно не нужны, мы привыкли к рутине. Наконец, Java 8 больше не выдержала, и был введен Optional, чтобы код, который мы писали, не был таким подлым и жестким.
01. В чем проблема без опциона
Давайте смоделируем реальный сценарий приложения. Когда Сяо Ван вышел на работу в свой первый день, лидер Лао Ма устроил ему задачу, попросив вытащить имя участника из базы данных по идентификатору участника, а затем вывести имя в консоль. Хотя он здесь новичок, для Сяо Вана эта задача не представляет сложности, поэтому он потратил 10 минут на написание этого кода:
public class WithoutOptionalDemo {
class Member {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
Member mem = getMemberByIdFromDB();
if (mem != null) {
System.out.println(mem.getName());
}
}
public static Member getMemberByIdFromDB() {
// 当前 ID 的会员不存在
return null;
}
}
Поскольку член с текущим идентификатором не существует, поэтомуgetMemberByIdFromDB()
Метод возвращает null как результат отсутствия члена, а это означает, что при печати имени члена mem должен сначала быть нулевым, иначе будет выдано исключение NPE, вы мне не верите? пусть корольif (mem != null)
Попробуйте удалить его, консоль сразу распечатает стек ошибок, чтобы показать вам цвет.
Exception in thread "main" java.lang.NullPointerException
at com.cmower.dzone.optional.WithoutOptionalDemo.main(WithoutOptionalDemo.java:24)
02. Как опцион решает эту проблему
После того, как Сяо Ван представил код, он с радостью подошел к старой лошади, чтобы попросить новое задание. Смиренно стремясь к обучению, Сяо Ван попросил Лао Ма взглянуть на его код, поэтому Лао Ван сказал ему, что ему следует попробовать опционально, чтобы избежать ненужных проверок нулевых значений. Теперь давайте посмотрим, как Сяо Ван решает указанную выше проблему с помощью опциона.
public class OptionalDemo {
public static void main(String[] args) {
Optional<Member> optional = getMemberByIdFromDB();
optional.ifPresent(mem -> {
System.out.println("会员姓名是:" + mem.getName());
});
}
public static Optional<Member> getMemberByIdFromDB() {
boolean hasName = true;
if (hasName) {
return Optional.of(new Member("沉默王二"));
}
return Optional.empty();
}
}
class Member {
private String name;
public String getName() {
return name;
}
// getter / setter
}
getMemberByIdFromDB()
метод возвращенOptional<Member>
В результате это указывает на то, что Member может существовать, а может и не существовать, и в этом случае его можно использовать в опциональном элементе.ifPresent()
Лямбда-выражение используется в методе для прямой печати результата.
Причина, по которой Optional может решить проблему NPE, заключается в том, что он ясно говорит нам, что его не нужно аннулировать. Это как дорожный знак на перекрестке, который точно указывает, куда идти.
03. Создайте необязательный объект
1) Вы можете использовать статические методыempty()
Создает пустой необязательный объект
Optional<String> empty = Optional.empty();
System.out.println(empty); // 输出:Optional.empty
2) Вы можете использовать статические методыof()
Создайте непустой необязательный объект
Optional<String> opt = Optional.of("沉默王二");
System.out.println(opt); // 输出:Optional[沉默王二]
Конечно переходимof()
Параметры метода должны быть ненулевыми, то есть не нулевыми, иначе все равно будет выброшено исключение NullPointerException.
String name = null;
Optional<String> optnull = Optional.of(name);
3) Вы можете использовать статические методыofNullable()
Создайте необязательный объект, который может быть как нулевым, так и необнуляемым.
String name = null;
Optional<String> optOrNull = Optional.ofNullable(name);
System.out.println(optOrNull); // 输出:Optional.empty
ofNullable()
Внутри метода есть троичное выражение, если параметр равен null, возвращается приватная константа EMPTY, в противном случае создается новый объект Optional с использованием ключевого слова new — исключение NPE не генерируется.
04. Определите, существует ли значение
через методisPresent()
Определяет, существует ли необязательный объект, если да, то метод возвращает true, в противном случае возвращает false — заменяетсяobj != null
суждение.
Optional<String> opt = Optional.of("沉默王二");
System.out.println(opt.isPresent()); // 输出:true
Optional<String> optOrNull = Optional.ofNullable(null);
System.out.println(opt.isPresent()); // 输出:false
После Java 11 также можно передавать методыisEmpty()
Суждение иisPresent()
противоположный результат.
Optional<String> opt = Optional.of("沉默王二");
System.out.println(opt.isPresent()); // 输出:false
Optional<String> optOrNull = Optional.ofNullable(null);
System.out.println(opt.isPresent()); // 输出:true
05. Непустые выражения
Необязательный класс имеет очень современный подход -ifPresent()
, что позволяет нам выполнять некоторый код с помощью функционального программирования, поэтому я называю его непустым выражением. Без этого метода нам обычно нужно передатьisPresent()
Необязательный метод определения объекта, а затем выполните соответствующий нулевой код:
Optional<String> optOrNull = Optional.ofNullable(null);
if (optOrNull.isPresent()) {
System.out.println(optOrNull.get().length());
}
имеютifPresent()
После этого ситуация совсем другая, можно напрямую передать лямбда-выражение в метод, код лаконичнее и понятнее.
Optional<String> opt = Optional.of("沉默王二");
opt.ifPresent(str -> System.out.println(str.length()));
После Java 9 также можно передавать методыifPresentOrElse(action, emptyAction)
Выполнить два результата, выполнить действие, когда оно не пусто, и выполнить пустое действие, когда оно пусто.
Optional<String> opt = Optional.of("沉默王二");
opt.ifPresentOrElse(str -> System.out.println(str.length()), () -> System.out.println("为空"));
06. Установить (получить) значения по умолчанию
Иногда, когда мы создаем (получаем) необязательный объект, нам нужно значение по умолчанию,orElse()
иorElseGet()
метод пригодится.
orElse()
Метод используется для возврата значения, завернутого в необязательный объект, если значение не равно нулю, возврат; в противном случае вернуть значение по умолчанию. Тип параметра метода совпадает с типом значения.
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("沉默王二");
System.out.println(name); // 输出:沉默王二
orElseGet()
метод сorElse()
Методы похожи, но типы параметров разные. Если значение в необязательном объекте равно null, выполняется функция в параметре.
String nullName = null;
String name = Optional.ofNullable(nullName).orElseGet(()->"沉默王二");
System.out.println(name); // 输出:沉默王二
По выводу и виду кода эти два метода очень похожи, что неизбежно приводит нас к сомнению, а нужно ли это делать проектировщикам библиотеки классов Java?
Предположим, есть способ получить значение по умолчанию, очень традиционный способ.
public static String getDefaultValue() {
System.out.println("getDefaultValue");
return "沉默王二";
}
Затем, поorElse()
Методы иorElseGet()
методы вызываются отдельноgetDefaultValue()
Метод возвращает значение по умолчанию.
public static void main(String[] args) {
String name = null;
System.out.println("orElse");
String name2 = Optional.ofNullable(name).orElse(getDefaultValue());
System.out.println("orElseGet");
String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue);
}
Примечание:类名 :: 方法名
Является ли синтаксис, представленный Java 8, за именем метода не следует()
, указывая на то, что метод не обязательно будет вызываться.
Результат выглядит следующим образом:
orElse
getDefaultValue
orElseGet
getDefaultValue
Вывод аналогичен, не сильно отличается, это в случае, если необязательный объект имеет значение null . Что делать, если значение необязательного объекта не равно нулю?
public static void main(String[] args) {
String name = "沉默王三";
System.out.println("orElse");
String name2 = Optional.ofNullable(name).orElse(getDefaultValue());
System.out.println("orElseGet");
String name3 = Optional.ofNullable(name).orElseGet(OrElseOptionalDemo::getDefaultValue);
}
Результат выглядит следующим образом:
orElse
getDefaultValue
orElseGet
Какие,orElseGet()
не звонилgetDefaultValue()
. Какой метод более эффективен, вы поняли?
07. Получите ценность
Интуитивно, семантически,get()
Этот метод является наиболее аутентичным способом получить значение необязательного объекта, но, к сожалению, этот метод несовершенен, поскольку, если значение необязательного объекта равно нулю, метод выдаст исключение NoSuchElementException. Это полностью противоречит цели использования класса Optional.
public class GetOptionalDemo {
public static void main(String[] args) {
String name = null;
Optional<String> optOrNull = Optional.ofNullable(name);
System.out.println(optOrNull.get());
}
}
Эта программа выдает исключение при запуске:
Exception in thread "main" java.util.NoSuchElementException: No value present
at java.base/java.util.Optional.get(Optional.java:141)
at com.cmower.dzone.optional.GetOptionalDemo.main(GetOptionalDemo.java:9)
Несмотря на то, что выбрасывается исключение NoSuchElementException вместо NPE, нам кажется, что это «пятьдесят шагов из ста шагов». предположениеorElseGet()
Метод получает значение необязательного объекта.
08. Значение фильтра
Сяо Ван обновил предыдущий код через класс Optional, а после завершения с радостью отправился к старому коню просить задание. Лао Ма подумал, что этот молодой человек хороший, гибкий и активный, достоин обучения, поэтому дал Сяо Вану новое задание: проверить длину пароля при регистрации пользователя.
После того, как Сяо Ван получил задание, он был счастлив, потому что он как раз собирался изучать Факультативный класс.filter()
метод, который пригодится.
public class FilterOptionalDemo {
public static void main(String[] args) {
String password = "12345";
Optional<String> opt = Optional.ofNullable(password);
System.out.println(opt.filter(pwd -> pwd.length() > 6).isPresent());
}
}
filter()
Тип параметра метода — Predicate (новый функциональный интерфейс, добавленный в Java 8), что означает, что лямбда-выражение может быть передано методу в качестве условия.Если результат выражения ложный, возвращается ПУСТОЙ необязательный объект. , В противном случае возвращает отфильтрованный необязательный объект.
В приведенном выше примере, поскольку длина пароля равна 5, результат вывода программы — ложь. Предполагая, что длина пароля составляет от 6 до 10 цифр, можно добавить еще одно условие. Давайте посмотрим на код Сяо Вана после увеличения сложности.
Predicate<String> len6 = pwd -> pwd.length() > 6;
Predicate<String> len10 = pwd -> pwd.length() < 10;
password = "1234567";
opt = Optional.ofNullable(password);
boolean result = opt.filter(len6.and(len10)).isPresent();
System.out.println(result);
На этот раз программа выводит истину, потому что пароль стал 7-значным, между 6 и 10 цифрами. Представьте, насколько подробным был бы код, если бы Сяо Ван использовал if-else для выполнения этой задачи.
09. Ценность конверсии
После того, как Сяо Ван проверил длину пароля, он все еще чувствовал, что он недостаточно счастлив.Он чувствовал, что следует также проверить надежность пароля.Например, пароль не может быть «пароль», который слишком слаб. Поэтому он начал исследоватьmap()
метод, который может преобразовать исходный необязательный объект в новый необязательный объект в соответствии с определенными правилами, и исходный необязательный объект не будет изменен.
Давайте сначала рассмотрим простой пример, написанный Сяо Ваном:
public class OptionalMapDemo {
public static void main(String[] args) {
String name = "沉默王二";
Optional<String> nameOptional = Optional.of(name);
Optional<Integer> intOpt = nameOptional
.map(String::length);
System.out.println( intOpt.orElse(0));
}
}
В приведенном выше примереmap()
параметры методаString::length
, что означает повторное создание нового объекта Optional типа Integer в соответствии с длиной исходной строки типа Optional.
догадатьсяmap()
После основного использования метода Сяо Ван решил поставитьmap()
метод сfilter()
Этот метод используется в комбинации, первый используется для преобразования пароля в нижний регистр, а второй используется для определения длины и того, является ли он «паролем».
public class OptionalMapFilterDemo {
public static void main(String[] args) {
String password = "password";
Optional<String> opt = Optional.ofNullable(password);
Predicate<String> len6 = pwd -> pwd.length() > 6;
Predicate<String> len10 = pwd -> pwd.length() < 10;
Predicate<String> eq = pwd -> pwd.equals("password");
boolean result = opt.map(String::toLowerCase).filter(len6.and(len10 ).and(eq)).isPresent();
System.out.println(result);
}
}
Ну что, мои дорогие читатели и друзья, выше все содержание этой статьи - можно сказать, что это лучшее Факультативное руководство в истории, вы видите здесь лучшие программисты, второй брат должен поставить палец вверх Вам нравится Это.
Если вы считаете, что статья полезна для вас, пожалуйста, выполните поиск по запросу "Тихий король 2"Прочтите это в первый раз, ответьте [666】【1024] Я также тщательно подготовил для вас обучающие видео высокой четкости 500G (которые были разделены на категории), а также копию интервью, организованных техническими экспертами Дачанга.Исходный код этой статьи был включены в облако кода,портал~