Java8 — необязательно

Java
Java8 — необязательно

Это первый раз, когда я участвую в Gengwen Challenge.19День, подробности о событии уточняйте:Обновить вызов

Со временем капли воды и камни изнашиваются 😄

Что необязательно

OptionalдаJAVA8новая особенность .OptionalКласс находится вjava.utilПод пакетом это означает, что на самом деле это класс инструмента.

Давайте посмотрим, как официальное введениеOptionalиз.

image.png

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);
}

image-20201226205000800.png

  • Optional.empty() : создать пустойOptionalПример

Если вы просто хотите создать нульOptionalНапример, вы можете использовать этот метод.

@Test
public void test2(){
    Optional<Student> student = Optional.empty();
    Student student1 = student.get();
    System.out.println(student1);
}

image-20201226205234868.png

Должен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);
}

image.png

  • <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Ждать.

  • Если у вас есть какие-либо вопросы по этой статье или есть ошибки в этой статье, пожалуйста, оставьте комментарий. Если вы считаете, что эта статья была вам полезна, ставьте лайк и подписывайтесь на нее.