Объясните своей девушке, что необязательно [функции JDK 8]

Java задняя часть программист контейнер

предисловие

Только лысина может стать сильнее

Два дня назад водил свою девушку в библиотеку и принес ей книгу "Изучаем программирование с детьми", так что сегодня я объясню своей девушке, что такое Факультативный класс.

  • Что касается того, могла ли она понять это, она, конечно, не могла этого понять. (Как это может понять женщина, изучившая переменные/циклы for)

Я не знаю, помнишь ли ты еще предыдущую.После прочтения "Руководства по разработке Java для Alibaba"Нет, когда я читал об исключении нулевого указателя (NPE), в книге упоминалось, что JDK 8 имеет необязательный класс для использования, который может максимально предотвратить исключение нулевого указателя (NPE).

текстСтремитесь объяснить каждый пункт знаний просто, я надеюсь, что каждый сможет что-то получить после прочтения

1. Основная мощение

Мы все знаем, что самые важные новые функции JDK 8LambdaExpression, это позволяет нам упростить написание большого количества кода, я не знаю, будете ли вы его использовать. Здесь я кратко рассмотрю это с вами ~

1.1 Пример упрощенного кода Lambda

Ниже приведеннесколько примеровДавайте посмотрим, как лямбда-выражения упрощают написание нашего кода.

Сначала давайте посмотрим насоздать тему:


public static void main(String[] args) {
    // 用匿名内部类的方式来创建线程
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("公众号:Java3y---回复1进群交流");
        }
    });

    // 使用Lambda来创建线程
    new Thread(() -> System.out.println("公众号:Java3y---回复1进群交流"));
}

Давайте снова посмотрим на обход коллекции Map:



public static void main(String[] args) {
    Map<String, String> hashMap = new HashMap<>();
    hashMap.put("公众号", "Java3y");
    hashMap.put("交流群", "回复1");

    // 使用增强for的方式来遍历hashMap
    for (Map.Entry<String, String> entry : hashMap.entrySet()) {
        System.out.println(entry.getKey()+":"+entry.getValue());
    }

    // 使用Lambda表达式的方式来遍历hashMap
    hashMap.forEach((s, s2) -> System.out.println(s + ":" + s2));
}

Удалить элемент из списка


public static void main(String[] args) {

    List<String> list = new ArrayList<>();
    list.add("Java3y");
    list.add("3y");
    list.add("光头");
    list.add("帅哥");
    
    // 传统的方式删除"光头"的元素
    ListIterator<String> iterator = list.listIterator();
    while (iterator.hasNext()) {
        if ("光头".equals(iterator.next())) {
            iterator.remove();
        }
    }

    // Lambda方式删除"光头"的元素
    list.removeIf(s -> "光头".equals(s));
    
    // 使用Lambda遍历List集合
    list.forEach(s -> System.out.println(s));
}

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

1.1 Функциональный интерфейс

Использование лямбда-выражений, по сути, основано нафункциональный интерфейсВверх. Давайте посмотрим на интерфейс вышеуказанного кода:

Интерфейс Runnable для создания нескольких потоков:


@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

Пройдите через интерфейс BiConsumer HashMap:


@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
        Objects.requireNonNull(after);
        return (l, r) -> {
            accept(l, r);
            after.accept(l, r);
        };
    }
}

Интерфейс предиката для удаления элементов в списке:


@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Особенности функционального интерфейса:@FunctionalInterfaceИдентификатор аннотации, интерфейсесть и толькоАбстрактный метод!

1.2 Краткое объяснение Lambda

Возможно, когда мы впервые увидели Lambda, мы обнаружили, что синтаксис лямбда-выражений был немного странным или даже немного непонятным. Ничего страшного, вот 3й рисует картинку в виде картинки:

Lambda表达式组成

В качестве примера возьмем интерфейс Runnable:

Lambda表达式很简单!

Как бы это ни было плохо, когда мы используем IDE, мы можем подсказать синтаксис лямбда-выражений, что может помочь нам быстро начать работу с лямбда-выражениями:

IDEA提示Lambda表达式

Грубо говоря, полка, на которой мы используем лямбда-выражения, выглядит так:()->{}, просто посмотрите требования к абстрактному методу функционального интерфейса, если он специфичен, и если этого недостаточно, используйте интеллектуальную подсказку IDE.

1.3 Обзор дженериков

Напримерpublic<U> Optional<U> map(Function<? super T, ? extends U> mapper)Вы понимаете это утверждение?


// 接口
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

В верхней и нижней границах дженериков действует принцип: PECS (Producer Extends Consumer Super)

  • С квалификациями подкласса можно прочитать из дженериков [то есть --->(? extend T)]------->Producer Extensions
  • С квалификацией суперкласса его можно записать из дженериков [то есть --->(? super T)]------->Consumer Super

Анализ: входящий параметр — это универсальный T или его родительский класс, а возвращаемое значение — U или его подкласс.

Для получения подробной информации см.:

Во-вторых, необязательный класс

Представьте дополнительный класс в одном предложении: используйте дополнительный класс JDK8, чтобы предотвратить проблемы NPE (исключение нулевого указателя).

Далее давайте посмотрим, что говорится в документации:

A container object which may or may not contain a non-null value.Additional methods that depend on the presence or absence of a contained value are provided

этоконтейнер, загруженный элементами, отличными от NULL (или без элементов), предоставляет нам ряд методов, позволяющих определить, существует ли объект в контейнере (и последующие операции).

Способ необязательного класса:

Optional类的方法结构图

2.1 Создайте необязательный контейнер

Давайте сначала посмотрим на свойства необязательных и как создать необязательный контейнер:


	// 1、创建出一个Optional容器,容器里边并没有装载着对象
    private static final Optional<?> EMPTY = new Optional<>();

	// 2、代表着容器中的对象
    private final T value;

	// 3、私有构造方法
    private Optional() {
        this.value = null;
    }

	// 4、得到一个Optional容器,Optional没有装载着对象
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

	// 5、私有构造方法(带参数),参数就是具体的要装载的对象,如果传进来的对象为null,抛出异常
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

	// 5.1、如果传进来的对象为null,抛出异常
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }


	// 6、创建出Optional容器,并将对象(value)装载到Optional容器中。
	// 传入的value如果为null,抛出异常(调用的是Optional(T value)方法)
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

	// 创建出Optional容器,并将对象(value)装载到Optional容器中。
	// 传入的value可以为null,如果为null,返回一个没有装载对象的Optional对象
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

Таким образом, можно сделать вывод, что создание дополнительного контейнерадваСпособ:

  • Вызовите метод ofNullable(), входящий объект может быть нулевым
  • Вызовите метод of(), входящий объект не может быть нулевым, иначе будет выброшено исключение NullPointerException.

Вот простой взгляд на то, как его использовать:

Теперь у меня есть объект User, и здесь используется Lombok, заинтересованные студенты могут узнать о нем:Двухмесячная стажировка по Java завершена, продолжайте усердно работать


import lombok.Data;
@Data
public class User {

    private Integer id;
    private String name;
    private Short age;
}

контрольная работа:


public static void main(String[] args) {

    User user = new User();
    User user1 = null;

    // 传递进去的对象不可以为null,如果为null则抛出异常
    Optional<User> op1 = Optional.of(user1);

    // 传递进去的对象可以为null,如果为null则返回一个没有装载对象的Optional容器
    Optional<User> op2 = Optional.ofNullable(user);
}

结果

2.2 Простой метод дополнительного контейнера


// 得到容器中的对象,如果为null就抛出异常
public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

// 判断容器中的对象是否为null
public boolean isPresent() {
    return value != null;
}

// 如果容器中的对象存在,则返回。否则返回传递进来的参数
public T orElse(T other) {
    return value != null ? value : other;
}

Эти три метода являются более часто используемыми методами дополнительного класса и являются самыми простыми. (Потому что параметр не является функциональным интерфейсом)

Здесь мы продолжаем смотреть на использование:


public static void main(String[] args) {

        User user = new User();
        User user1 = null;

        Optional<User> op1 = Optional.ofNullable(user);
        System.out.println(op1.isPresent());
        System.out.println(op1.get());
        System.out.println(op1.orElse(user1));

    }

Результат очевиден, ведь наш пользователь не null:

结果

Давайте поменяем порядок и посмотрим:


public static void main(String[] args) {

    User user = new User();
    User user1 = null;

    Optional<User> op1 = Optional.ofNullable(user1);
    System.out.println(op1.isPresent());
    System.out.println(op1.orElse(user));
    System.out.println(op1.get());

}

结果

2.3 Расширенное использование дополнительного контейнера

Конечно, пока кажется, что класс Optional выглядит так же, поэтому код не так хорош, как я оцениваю null...

мыВ сравнениинемного:

对比

мы можем узнать,руководствоПредставляется более удобным и лаконичным судить о том, является ли оно нулевым или нет.

Итак, наш метод с функциональным интерфейсом!

2.3.1 Метод ifPresent

Первый взглядifPresent(Consumer<? super T> consumer)метод



public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

Если объект в контейнере существует, вызывается метод Accept, например:


public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果存在user,则打印user的name
    optional.ifPresent((value) -> System.out.println(value.getName()));

    // 旧写法
    if (user != null) {
        System.out.println(user.getName());
    }
}

2.3.2 Методы OrELSEGET и ORELSETHROW

Посмотрите прямо на исходный код:


// 如果对象存在,则直接返回,否则返回由Supplier接口的实现用来生成默认值
public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}


@FunctionalInterface
public interface Supplier<T> {
    T get();
}


// 如果存在,则返回。否则抛出supplier接口创建的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

пример:


public static void main(String[] args) {

    User user = new User();
    user.setName("Java3y");
    test(user);
}

public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果存在user,则直接返回,否则创建出一个新的User对象
    User user1 = optional.orElseGet(() -> new User());
    
    // 旧写法
    if (user != null) {
        user = new User();
    }
}

В общем то, что мы сказали вышеorElse()Аналогично, за исключением того, что может генерировать значения по умолчанию через реализацию интерфейса Supplier.

2.3.3метод фильтрации

Посмотрите прямо на исходный код:


// 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}


// 接口
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}

Возвращая необязательный объект, которого мы можем достичьцепной вызов!

пример:


public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果容器中的对象存在,并且符合过滤条件,返回装载对象的Optional容器,否则返回一个空的Optional容器
    optional.filter((value) -> "Java3y".equals(value.getName()));
}

2.3.4 метод карты

Посмотрите прямо на исходный код:


// 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional。
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));
    }
}


// 接口
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

пример:


public static void test(User user) {

    Optional<User> optional = Optional.ofNullable(user);

    // 如果容器的对象存在,则对其执行调用mapping函数得到返回值。然后创建包含mapping返回值的Optional,否则返回空Optional。
    optional.map(user1 -> user1.getName()).orElse("Unknown");
}

// 上面一句代码对应着最开始的老写法:

public String tradition(User user) {
    if (user != null) {
        return user.getName();
    }else{
        return "Unknown";
    }
}

2.3.5 Метод плоской карты

Посмотрите прямо на исходный код:


// flatMap方法与map方法类似,区别在于apply函数的返回值不同。map方法的apply函数返回值是? extends U,而flatMap方法的apply函数返回值必须是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));
    }
}

2.3.6 Резюме

Почувствуйте очарование опциона снова


public static void main(String[] args) {
    User user = new User();
    user.setName("Java3y");
    System.out.println(test(user));
}

// 以前的代码v1
public static String test2(User user) {
    if (user != null) {
        String name = user.getName();
        if (name != null) {
            return name.toUpperCase();
        } else {
            return null;
        }
    } else {
        return null;
    }
}

// 以前的代码v2
public static String test3(User user) {
    if (user != null && user.getName() != null) {
        return user.getName().toUpperCase();
    } else {
        return null;
    }
}

// 现在的代码
public static String test(User user) {
    return Optional.ofNullable(user)
            .map(user1 -> user1.getName())
            .map(s -> s.toUpperCase()).orElse(null);
}

НеобязательныйСводка:

filter, map или flatMap — это функция, значение параметра функции не должно быть нулевым. Таким образом, мы можем безопасно преобразовать его с помощью таких функций, как filter, map и flatMap, и, наконец, извлечь значение с помощью серий orElse, get, isPresent и ifPresent.

На самом деле использование класса Optional не упрощает код, а скрывает NPE-исключение с помощью различных методов (обернув слой). Использование лямбда-выражений может сделать нашу обработку более "милость"Немного.

3. Наконец

Когда я был новичком, меня не волновали возможности JDK8, на самом деле обновления JDK могут принести нам много пользы (упростить написание кода, повысить производительность и т. д.), поэтому мне, как Java-программисту, все равно нужно узнать больше Новые функции. (Говоря о JDK9, у этого класса есть новые функции...)

Если вы собираетесь комментировать "Просыпайтесь, где девушка программиста", "Писаю, дайте кончить" и т.д., то предлагаю вамхорошее отражениеСпросите себя, почему у других программистов есть девушки, а у вас нет, может быть, ваши навыки недостаточно хороши? Неужели так сложно найти его через "фабрику"? Как бы плохо это ни было, вы можете сами придумать новое.

Конечно, моя девушка настоящая.

Использованная литература:

Если вы думаете, что я написал хорошо, проверьте:

  • настаиватьоригинальныйТехнический общедоступный номер: Java3y.
  • статьиНавигация по каталогу(Изысканная карта мозга + огромные видеоресурсы):GitHub.com/Zhongf UC очень…