[Продвинутое программирование на Java] Новые возможности Java8

вставьте сюда описание изображения

Новые возможности Java8

1. Обзор новых возможностей Java8

  • функциональный интерфейс
  • Лямбда-выражение
  • ссылка на метод/ссылка на конструктор
  • Потоковое API
    • параллельный поток
    • последовательный поток
  • Улучшения интерфейса
    • статический метод
    • метод по умолчанию
  • Необязательный класс
  • Новый API времени и даты
  • Другие новые функции
    • Дублировать аннотацию
    • введите аннотацию
    • Общий вывод типа объекта
    • Обновление JDK
      • Потоковые операции над коллекциями
      • параллелизм
      • Массивы
      • Число и математика
      • Улучшения IO/NIO
      • Отражение получает формальное имя параметра
      • Строка: присоединиться()
      • Файлы
    • Новые инструменты компиляции: jjs, jdeps
    • Metaspace заменяет пространство PermGen в JVM

2. Лямбда-выражение

2.1 Сравнение до и после использования лямбда-выражений

@Test
public void test1 () {
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("我爱北京天安门");
        }
    };
    r1.run();
    // 使用lambda表达式
    Runnable r2 = () -> System.out.println("我爱北京天安门");
    r2.run();
}
@Test
public void test2 () {
    Comparator<Integer> com1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    System.out.println(com1.compare(12, 21));
    // Lambda表达式的写法
    Comparator<Integer> com2 = (o1, o2) -> Integer.compare(o1, o2);
    System.out.println(com2.compare(32, 21));
    // 方法引用
    Comparator<Integer> com3 = Integer :: compare;
    System.out.println(com3.compare(32, 21));
}

2.2 Базовая грамматика лямбда-выражения

  • Пример: (o1, o2) -> Integer.compare(o1, o2);
  • Формат:
    • ->: лямбда-оператор или оператор стрелки
    • -> Слева: список формальных параметров лямбда (фактически список формальных параметров абстрактного метода в интерфейсе)
    • -> Справа: тело лямбда (на самом деле тело метода переписанного абстрактного метода)

2.3, как использовать: разделить на шесть ситуаций

  • Формат грамматики 1: без параметра, без возвращаемого значения
    • Runnable r1 = () -> {System.out.println("Hello Lambda!");};
  • Формат грамматики 2: Lambda требует параметр, но не имеет возвращаемого значения
    • Consumer<String> con = (String str) -> {System.out.println(str);};
  • Формат синтаксиса 3: тип данных может быть опущен, поскольку он может быть выведен компилятором, что называется «выводом типа».
    • Consumer<String> con = (str) -> {System.out.println(str);};
  • Формат грамматики 4: если Lambda нужен только один параметр, круглые скобки параметра можно опустить.
    • Consumer<String> con = str -> {System.out.println(str);};
  • Пятый формат грамматики: Lambda требует двух или более параметров, нескольких операторов выполнения и может иметь возвращаемое значение.
    • Comparator<Integer> com = (x, y) -> {System.out.println("实现函数式接口方法!"); return Integer.compare(x, y);};
  • Формат грамматики 6: когда тело Lambda содержит только один оператор, return и фигурные скобки, если они есть, можно опустить.
    • Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

Обобщим шесть ситуаций:
-> слева: тип параметра списка параметров лямбда может быть опущен (вывод типа); если список параметров лямбда имеет только один параметр, пара () также может быть опущена -> справа: тело лямбда должно используйте
пакет пары {}; если тело лямбда имеет только один оператор выполнения (вероятно, оператор возврата, опустите пару ключевых слов {} и return)

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

3.1 Инструкция по использованию функционального интерфейса

  • Если интерфейс объявляет только один абстрактный метод, интерфейс называется функциональным интерфейсом.
  • Мы можем аннотировать интерфейс с помощью @FunctionalInterface и при этом мы можем проверить, является ли он функциональным интерфейсом.
  • Суть лямбда-выражений: как экземпляров функциональных интерфейсов

3.2 Четыре основных функциональных интерфейса, предоставляемых лямбда-выражениями в Java8

функциональный интерфейс Тип параметра возвращаемый тип использовать
Consumer<T>потребительский интерфейс Т пустота Применить операцию к объекту типа T, включая метод: void accept(T t)
Supplier<T>интерфейс питания никто Т Возвращает объект типа T, включая метод: T get()
Function<T, R>функциональный интерфейс Т р Применяет операцию к объекту типа T и возвращает результат. Результатом является объект типа R. Включить метод: R применить (T t)
Predicate<T>интерфейс утверждения Т логический Определяет, удовлетворяет ли объект типа T ограничению, и возвращает логическое значение. Содержит метод: логический тест (T t)

3.3. Резюме

  • Когда использовать лямбда-выражения?
    • Когда вам нужно создать экземпляр функционального интерфейса, вы можете использовать лямбда-выражения
  • Когда использовать данный функциональный интерфейс?
    • Если нам нужно определить функциональный интерфейс во время разработки, сначала проверьте, обеспечивает ли функциональный интерфейс, предоставляемый существующим JDK, функциональный интерфейс, который может соответствовать требованиям. Если есть, вы можете вызвать его напрямую, и вам не нужно настраивать его самостоятельно.

4. Ссылка на метод

4.1. Понимание

  • Ссылку на метод можно рассматривать как глубокое выражение лямбда-выражения. Другими словами, ссылка на метод — это лямбда-выражение, которое является экземпляром функционального интерфейса, указывающим на метод по его имени.

4.2. Сценарии использования

  • Когда операция, которая должна быть передана в тело Lambda, уже имеет реализованный метод, вы можете использовать ссылку на метод

4.3 Формат

  • класс (или объект) :: имя метода

4.4, разделенный на следующие три ситуации

  • Object:: нестатический метод --> Случай 1
  • класс:: статический метод --> случай 2
  • class:: нестатический метод --> case 3

4.5 Требования

  • Список формальных параметров и тип возвращаемого значения абстрактного метода в интерфейсе должны совпадать со списком формальных параметров и типом возвращаемого значения метода, на который ссылается метод! (для случая 1 и случая 2)
  • Когда первый параметр метода функционального интерфейса — это вызывающая сторона, которая должна ссылаться на метод, а второй параметр — это параметр (или не параметр), который должен ссылаться на метод: ClassName::methodName (для случая 3)

4.6 Рекомендации по использованию

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

4.7 Примеры использования

// 情况一:对象 :: 实例方法
// Consumer中的void accept(T t)
// PrintStream中的void println(T t)
@Test
public void test1 () {
    Consumer<String> con1 = str -> System.out.println(str);
    con1.accept("北京");
    // 方法引用
    PrintStream ps = System.out;
    Consumer<String> con2 = ps::println;
    con2.accept("beijing");
}
// 情况二:类 :: 静态方法
// Comparator中int compare(T t1, T t2)
// Integer中的int compare(T t1, T t2)
@Test
public void test3 () {
    Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1, t2);
    System.out.println(com1.compare(12,21));
    // 方法引用
    Comparator<Integer> com2 = Integer::compare;
    System.out.println(com2.compare(12, 3));
}
// 情况三:类 :: 实例方法
// Comparator中的int compare(T t1, T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5 () {
    Comparator<String> com1 = (s1, s2) -> s1.compareTo(s2);
    System.out.println(com1.compare("abc", "abd"));
    // 方法引用
    Comparator<String> com2 = String :: compareTo;
    System.out.println(com2.compare("adb", "abm"));
}

5. Ссылка на конструктор и ссылка на массив

5.1 Формат ссылки на конструктор

  • имя класса:: новое

5.2 Требования к использованию ссылки на конструктор

  • Подобно ссылкам на методы, список формальных параметров абстрактного метода функционального интерфейса совпадает со списком формальных параметров конструктора. Тип возвращаемого значения абстрактного метода — это тип класса, к которому принадлежит конструктор.

5.3 Примеры ссылок на конструктор

// 构造器引用
// Supplier的T get()
// Employee的空参构造器:Employee()
@Test
public void test1 () {
    Supplier<Employee> sup = new Supplier<Employee>() {
        @Override
        public Employee get() {
            return new Employee();
        }
    };
    // lambda表达式
    Supplier<Employee> sup1 = () -> new Employee();
    System.out.println(sup1.get());
    // 构造器引用
    Supplier<Employee> sup2 = Employee :: new;
    System.out.println(sup2.get());
}
// Function中的R apply(T t)
@Test
public void test2 () {
    Function<Integer, Employee> func1 = id -> new Employee(id);
    System.out.println(func1.apply(1001));
    // 构造器引用
    Function<Integer, Employee> func2 = Employee :: new;
    System.out.println(func2.apply(1002));
}

5.4 Формат ссылки на массив

  • ТипМассива[]::новый

5.5 Примеры ссылок на массивы

// 数组引用
// Function中的R apply(T t)
@Test
public void test4 () {
    Function<Integer, String[]> func1 = length -> new String[length];
    System.out.println(Arrays.toString(func1.apply(5)));
    // 数组引用
    Function<Integer, String[]> func2 = String[] :: new;
    System.out.println(Arrays.toString(func2.apply(10)));
}

6、Потоковое API

6.1. Понимание Stream API

  • Поток фокусируется на работе с данными и имеет дело с ЦП; сбор фокусируется на хранении данных и имеет дело с памятью.
  • Java 8 предоставляет набор API-интерфейсов, которые можно использовать для фильтрации, сортировки, сопоставления, сокращения и других операций с данными в памяти. Аналогично операциям, связанным с SQL, над таблицами в базе данных.

6.2, Примечания

  • Сам поток не хранит элементы
  • Stream не изменяет исходный объект. Вместо этого они возвращают новый поток, содержащий результат
  • Потоковые операции выполняются лениво. Это означает, что они ждут, пока результат не понадобится для выполнения.

6.3, Процесс использования потока

  • Создание экземпляра потока
  • Ряд промежуточных операций (фильтрация, отображение, ...)
  • прекратить операцию

6.4. На что следует обратить внимание при использовании процесса

  • Цепочка промежуточных операций для обработки данных источника данных
  • После выполнения завершающей операции выполняется цепочка промежуточных операций и выдаются результаты. После этого он больше не будет использоваться.

6.5. Шаг 1: Создание экземпляра потока

// 创建Stream方式一:通过集合
@Test
public void test1 () {
    List<Employee> employees = EmployeeData.getEmployees();
    // default Stream<E> stream():返回一个顺序流
    Stream<Employee> stream = employees.stream();
    // default Stream<E> parallelStream():返回一个并行流
    Stream<Employee> parallelStream = employees.parallelStream();
}
// 创建Stream方式二:通过数组
@Test
public void test2 () {
    int[] arr = new int[]{1,2,3,4,5,6};
    // 调用Arrays类的static <T> Stream<T> stream(T[] array):返回一个流
    IntStream stream = Arrays.stream(arr);
}
// 创建Stream方式三:通过Stream的of()
@Test
public void test3 () {
    Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
}
// 创建Stream方式四:创建无限流
@Test
public void test4 () {
    // 迭代
    // public static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    // 遍历前10个偶数
    Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
    // 生成
    // public static <T> Stream<T> generate(Supplier<T> s)
    Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

6.6 Шаг 2: Промежуточная операция

  • Скрининг и нарезка
    • filter(Predicate p): получить лямбда, исключить определенные элементы из потока
    • Different(): фильтровать, удалять повторяющиеся элементы с помощью hashCode() и equals() элементов, сгенерированных потоком.
    • limit(long maxSize): обрезать поток, чтобы его элементы не превышали заданное число
    • skip(long n): пропустить элементы и вернуть поток с отброшенными первыми n элементами. Если в потоке меньше n элементов, возвращается пустой поток. Дополнительно к limit(n)
  • карта
    • map(Function f): получает функцию в качестве параметра, которая будет применяться к каждому элементу и отображаться в новый элемент
    • mapToDouble(ToDoubleFunction f): получает в качестве параметра функцию, которая будет применяться к каждому элементу для создания нового DoubleStream.
    • mapToInt(ToIntFunction f): получает в качестве параметра функцию, которая будет применяться к каждому элементу для создания нового IntStream.
    • mapToLong(ToLongFunction f): получает в качестве параметра функцию, которая будет применяться к каждому элементу для создания нового LongStream.
    • flatMap(Function f): получает функцию в качестве параметра, заменяет каждое значение в потоке другим потоком, а затем объединяет все потоки в один поток.
  • Сортировать
    • sorted(): создает новый поток, отсортированный в естественном порядке.
    • sorted(Comparator com): дает новый поток, отсортированный в порядке компаратора

6.7. Шаг 3: Завершение операции

  • сопоставить и найти
    • allMatch(Predicate p): проверяет соответствие всех элементов
    • anyMatch(Predicate p): проверяет, соответствует ли хотя бы один элемент
    • noneMatch(Predicate p): проверяет, не совпадают ли все элементы
    • findFirst(): возвращает первый элемент
    • findAny(): возвращает любой элемент в текущем потоке
    • count(): возвращает общее количество элементов в потоке.
    • max(Comparator c): возвращает максимальное значение в потоке
    • min(Comparator c): возвращает минимальное значение в потоке
    • forEach(Consumer c): внутренняя итерация (использование интерфейса Collection требует, чтобы пользователь выполнял итерацию, которая называется внешней итерацией. Напротив, Stream API использует внутреннюю итерацию — он выполняет итерацию за вас)
  • снижение
    • reduce(T iden, BinaryOperator b): Элементы в потоке можно многократно комбинировать для получения значения. вернуть Т
    • уменьшить (BinaryOperator b): элементы в потоке можно многократно комбинировать для получения значения. возвращатьсяOptional<T>
  • собирать
    • collect(Collector c): преобразовать поток в другие формы. Получите реализацию интерфейса Collector, который используется для суммирования элементов в Stream (Collector предоставляет экземпляры через Collectors).
      • к списку()
      • устанавливать()
      • в коллекцию ()

7. Использование дополнительного класса

7.1. Понимание

  • Создан для решения проблемы нулевых указателей в Java!
  • Optional<T>Класс (java.util.Optional) — это класс-контейнер, который может содержать значение типа T, представляющее существование этого значения. Или просто сохраните значение null, указывающее, что значение не существует. В прошлом null использовался для обозначения отсутствия значения, но теперь Optional может лучше выразить эту концепцию. И может избежать исключения нулевого указателя.

7.2 Общие методы

@Test
public void test1 () {
    
    
    // empty():创建的Optional对象内部的value = null
    Optional<Object> op1 = Optional.empty();
    if (!op1.isPresent()) {
    
    
        // Optional封装的数据是否包含数据
        System.out.println("数据为空");
    }
    // 如果Optional封装的数据value为空,则get()报错。否则,value不为空时,返回value
    // System.out.println(op1.get());
}
@Test
public void test2 () {
    
    
    String str = "hello";
    // of(T t):封装数据t生成Optional对象,要求t非空,否则报错
    Optional<String> op1 = Optional.of(str);
    // get()通常与of()方法搭配使用。用于获取内部的封装的数据value
    String str1 = op1.get();
    System.out.println(str1);
}
@Test
public void test3 () {
    
    
    String str = "beijing";
    str = null;
    // ofNullable(T t):封装数据t赋给Optional内部的value。不要求t非空
    Optional<String> op1 = Optional.ofNullable(str);
    // orElse(T t1):如果Optional内部的value非空,则返回此value值。如果value为空,则返回t1
    String str2 = op1.orElse("shanghai");
    System.out.println(str2);
}

рекомендация

отblog.csdn.net/qq_51808107/article/details/131448546