Это первый раз, когда я участвую в Gengwen Challenge.19День, подробности о событии уточняйте:Обновить вызов
Со временем капли воды и камни изнашиваются 😄
Что необязательно
OptionalдаJAVA8новая особенность .OptionalКласс находится вjava.utilПод пакетом это означает, что на самом деле это класс инструмента.
Давайте посмотрим, как официальное введениеOptionalиз.
java.util.Optional— это объект-контейнер, который может содержать или не содержать ненулевые значения, то есть он может содержать значения типа T или просто null. Если значение существует, тоisPresent()метод вернет true, вызвав егоget()Метод возвращает это значение.
Какая польза от опционального
OptionalВведение класса в основном предназначено для устранения исключения нулевого указателя (NullPointerException). В нашем обычном развитии, я полагаю, вы столкнулись с наиболееExceptionэтоNullPointerException. Вы можете быть простым, вы можете написать следующий код:
String cardNo = student.getCard().getCardNo().toUpperCase();
появляется в приведенном выше кодеNullPointerExceptionСлишком много нештатных ситуаций, если не хочешь показатьсяNullPointerExceptionЕсли это ненормально, то необходимо вывести пустое суждение следующим образом:
String cardNoUpper = null;
if(student != null){
Card card = student.getCard();
if(card != null){
String cardNo = card.getCardNo();
if (cardNo != null){
cardNoUpper = cardNo.toUpperCase();
}
}
}
Видно, что в каждый метод можно добавлять только ненулевые проверки, поэтому читабельность и ремонтопригодность кода относительно плохие. Чтобы упростить этот процесс, мы можем использоватьOptional.OptionalПредоставляет множество полезных методов, поэтому нам не нужно выполнять явное обнаружение нулей.
Создайте два класса, давайте сначала научимсяOptionalкак пользоваться и как пользоваться.
public class Student {
private String name;
private Integer age;
private Double grades;
// Card
private Card card;
//get set toString省略
}
public class Card {
private String cardNo;
private String cardName;
}
Создайте необязательный экземпляр
СоздайтеOptionalЕсть три способа экземпляра, а именноof、empty、ofNullableТри статических метода. Далее мы представим их отдельно.
-
Optional.of(T t): СоздаватьOptionalэкземпляр t не должен быть нулевым;@Test public void test1(){ Optional<Student> student = Optional.of(new Student()); Student student1 = student.get(); System.out.println(student1); } 结果:Student{name='null', age=null, grades=null}Если параметр метода of имеет значение null, возникает исключение нулевого указателя. Исключение возникает при создании
Optionalвремя экземпляра.Пример счетчика:
@Test
public void test1(){
Optional<Student> student2 = Optional.of(null);
}
-
Optional.empty(): создать пустойOptionalПример
Если вы просто хотите создать нульOptionalНапример, вы можете использовать этот метод.
@Test
public void test2(){
Optional<Student> student = Optional.empty();
Student student1 = student.get();
System.out.println(student1);
}
ДолженNoSuchElementExceptionисключение происходит вget()при вызове метода.
-
Optional.ofNullable(T t): t может быть нулевым. Если ненулевой, построить с переданным значениемOptional; иначе вернуть пустое значениеOptional.
@Test
public void test3(){
Optional<Student> student = Optional.ofNullable(new Student());
Student student1 = student.get();
System.out.println(student1);
}
结果:Student{name='null', age=null, grades=null}
еслиofNullableПараметр передается в null, и результат такой же, какempty()метод тот же. Исходный код выглядит следующим образом:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
научился создаватьOptionalМетод экземпляра, давайте рассмотрим другие методы далее.
Определите, содержит ли необязательный контейнер объект
-
boolean isPresent()·: определяет, содержится ли значение, возвращает true, если значение существует, в противном случае возвращает false.
Пример:
@Test
public void test4(){
Optional<Student> student = Optional.ofNullable(new Student());
if(student.isPresent()){
Student student1 = student.get();
System.out.println(student1);
}
Optional<Student> student2 = Optional.ofNullable(null);
//取反
if (!student2.isPresent()) {
System.out.println("该对象为空值");
}
}
结果:
Student{name='null', age=null, grades=null}
该对象为空值
-
void ifPresent(Consumer<? super T> consumer): Буквальное отличие от вышеописанного метода. Если есть значение, выполнитьaccept.accept; иначе ничего не делать.
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
Пример:
@Test
public void test5(){
Optional<Student> student = Optional.ofNullable(new Student("新三", 18, 55.0));
student.ifPresent((x)-> {
x.setName("李四");
});
System.out.println(student.get());
}
结果:Student{name='李四', age=18, grades=55.0}
Получить объект дополнительного контейнера
-
T get(): Если вызывающий объект содержит значение, вернуть значение, в противном случае броситьNoSuchElementExceptionаномальный -
T orElse(T other): возвращает значение, если оно имеет значение, в противном случае возвращает указанный объект
Пример:
@Test
public void test6(){
Optional<Student> op = Optional.ofNullable(null);
// op 传入null,使用应返回我们指定的对象
Student st = op.orElse(new Student("新三", 18, 55.0));
System.out.println(st);
//传入Student
Optional<Student> op2 = Optional.ofNullable(new Student());
Student st2 = op2.orElse(new Student("新三", 18, 55.0));
System.out.println(st2);
}
Student{name='新三', age=18, grades=55.0}
Student{name='null', age=null, grades=null}
-
T orElseGet(Supplier<? extends T> other): вернуть его, если есть значение, в противном случае вернуть егоSupplierОбъекты, предоставляемые функциональными интерфейсами.
@Test
public void test7(){
Optional<Student> op = Optional.ofNullable(null);
Student st = op.orElseGet(()->{
//由于是一个函数式接口,里面可以写逻辑
Student student = new Student();
student.setAge(99);
student.setGrades(888.2);
student.setName("李四");
return student;
});
System.out.println(st);
}
结果:Student{name='李四', age=99, grades=888.2}k6a8
-
T orElseThrow(Supplier<? extends X> exceptionSupplier): верните его, если есть значение, в противном случае выбросьте егоSupplierИсключения, предоставляемые функциональными интерфейсами
@Test
public void test8(){
Optional<Student> op = Optional.ofNullable(null);
Student st = op.orElseThrow(() -> new RuntimeException("值不存在"));
System.out.println(st);
}
-
<U> Optional<U> map(Function<? super T, ? extends U> mapper): выполняется на нем, если есть значениеmapper.apply, и возвращает обработанныйOptional. в противном случае вернутьсяOptional.empty(). Исходный код выглядит следующим образом:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
Пример:
@Test
public void test9(){
Optional<Student> op = Optional.ofNullable(new Student("新,三", 18, 55.0));
Optional<String[]> s1 = op.map(s -> s.getName())
.map(s -> s.split(","));
System.out.println(Arrays.toString(s1.get()));
}
结果:[新, 三]
-
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):иmapАналогично, но требует, чтобы параметр былOptional.
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}
Пример:
@Test
public void test10(){
Optional<Student> op = Optional.ofNullable(new Student("新,三", 18, 55.0));
Optional<String[]> s1 = op.flatMap(s -> Optional.ofNullable(s.getName())
.flatMap(s2 -> Optional.ofNullable(s2.split(",")))
);
System.out.println(Arrays.toString(s1.get()));
}
结果:[新, 三]
-
Optional<T> filter(Predicate<? super T> predicate): если значение существует и условие предиката выполнено, вернуть значение значенияOptional, иначе возвратOptional.empty
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}
Пример:
@Test
public void test11(){
Optional<Student> optional = Optional.of(new Student("新三", 18, 55.0));
// 不符合断言条件 返回 Optional.empty
Optional<Student> opt = optional.filter(s -> {
return "张".equals(s.getName());
});
System.out.println(opt.orElse(new Student("李四", 22, 223.0)));
}
结果:Student{name='李四', age=22, grades=223.0}
здесьOptionalПредоставленные методы здесь почти закончены, следующим шагом является улучшение проблем, упомянутых в начале, как использоватьOptionalоптимизировать код?
String cardNoUpper = null;
if(student != null){
Card card = student.getCard();
if(card != null){
String cardNo = card.getCardNo();
if (cardNo != null){
cardNoUpper = cardNo.toUpperCase();
}
}
}
Сначала рефакторингStudentв классеgetCardметод, возвращающий егоOptionalЦитировать.
public class Student {
private String name;
private Integer age;
private Double grades;
private Card card;
// 其余省略。。。
public Optional<Card> getCard() {
return Optional.ofNullable(card);
}
public void setCard(Card card) {
this.card = card;
}
}
Подготовка завершена, приступаем к кодированию!
public static void main(String[] args) {
Student student = new Student("新三", 18, 55.0);
Card cardObj = new Card("ACafgtc", "工商银行");
student.setCard(cardObj);
//Optional<Student> o = Optional.ofNullable(null);
Optional<Student> o = Optional.ofNullable(student);
String cardNoUpper = o
.flatMap(s -> s.getCard()) // 获得 Optional<Card>
.map(card -> card.getCardNo()) // 获得 Card 内的 cardNo
.map(cardNo -> cardNo.toUpperCase())
.orElse("默认值");
System.out.println(cardNoUpper);
}
结果:ACAFGTC
можно и напрямуюStudentУстановите для него значение null, чтобы увидеть, произойдет ли исключение.
public static void main(String[] args) {
Optional<Student> o = Optional.ofNullable(null);
String cardNoUpper = o
.flatMap(s -> s.getCard()) // 获得 Optional<Card>
.map(card -> card.getCardNo()) // 获得 Card 内的 cardNo
.map(cardNo -> cardNo.toUpperCase())
.orElse("默认值");
System.out.println(cardNoUpper);
}
结果:默认值
Суммировать
заOptionalНекоторые люди считают, что нет необходимости изучать этот класс, потому что им кажется, что они не будут использовать его в своей работе. Идея на самом деле неверна, хотя мы не инкапсулируем возвращаемое значение нашего метода какOptional, но учитсяOptionalЭто еще очень нужно, чтобы не сказать лишнего, хотя бы понять и использовать. Поскольку сейчас многие библиотеки классов используютOptionalИнкапсулируйте возвращаемое значение, напримерSpring Data JPA, потоковый APIЖдать.
- Если у вас есть какие-либо вопросы по этой статье или есть ошибки в этой статье, пожалуйста, оставьте комментарий. Если вы считаете, что эта статья была вам полезна, ставьте лайк и подписывайтесь на нее.