1. Обзор
Улучшения в Java 8 более глубоки, чем любые изменения в истории. Постоянное совершенствование Java также является результатом изменений в экологии языка программирования, таких как необходимость обработки больших данных на нескольких ядрах, а ранее Java не поддерживала эту операцию.
До Java 8, если вы хотели использовать преимущества нескольких ядер компьютера, вам приходилось использовать потоки и иметь дело со сложной логикой синхронизации. Но в Java 8 вы можете легко использовать потоки, чтобы ваш код выполнялся на нескольких ядрах.
Кроме того, он заимствует контент из других языков и библиотек с открытым исходным кодом, таких как Scala, Guava и т. д. Подытожим основные функции или улучшения Java8:
- Функциональное программирование и лямбда-выражения;
- Потоковое программирование;
- Улучшения API времени;
- метод по умолчанию
2. Поведенческая параметризация
«Поведение» относится к методам, а «параметризация поведения» относится к передаче методов в качестве параметров.режим стратегии. Но Java8 просто использует лямбда-выражения для упрощения кода анонимных классов, делая анонимные классы более лаконичными. Вам не нужно много знать об этом фрагменте контента.
2.1 Базовый синтаксис лямбда-выражений
(parameters) -> expression // 表达式
(parameters) -> {statements;} // 语句,语句尾带分号且要用花括号括起来
Выше приведен базовый синтаксис Lambda, первая строка — использование выражений в Lambda, вторая строка — использование операторов в Lambda.
Вот несколько примеров использования лямбда-выражений:
public static void main(String...args) {
// 创建对象
ICreateObject createObject = Employee::new;
IExpression expression = employees -> employees.get(0);
// 可以进一步简化为 IExpression expression2 = List::isEmpty;
IExpression expression2 = employees -> employees.isEmpty();
IConsumeObject consumeObject = employee -> System.out.println(employee.name);
IAdd add = (a, b) -> a + b;
IAdd add1 = Java8LambdaExample::cal;
// 会报出不是Function接口异常
// Object object = Employee::new;
}
Из приведенного выше примера кода мы можем сделать некоторые выводы:
- Так называемый функциональный интерфейс относится к интерфейсу, который содержит только один метод не по умолчанию.
@FunctionalInterface
Аннотация указывает, что указанный интерфейс является функциональным интерфейсом; - Если в лямбде
->
Ниже приведен оператор, и когда оператор состоит только из одной строки, мы можем удалить фигурные скобки; - Когда вы хотите присвоить лямбда-выражение объекту, если объект не
函数接口
, затем IDEA предложит; - Также обратите внимание, что функциональные интерфейсы не могут создавать проверенные исключения.
Ниже мы суммируем некоторые примеры общих ссылок на методы:
в коде вышеEmployee::new
Это называется ссылкой на метод, и ниже приведен пример общей ссылки на метод:
серийный номер | Lambda | Ссылка на эквивалентный метод |
---|---|---|
1 | (Employee e)->e.getName() |
Employee::getName |
2 | (String s) -> System.out.println(s) |
System.out::println |
3 | (str, i) -> str.substring(i) |
String::substring |
Поэтому резюмируем ситуацию трех приведенных методов:
серийный номер | Lambda | Ссылка на эквивалентный метод |
---|---|---|
1 | (参数) -> 类名.静态方法(参数) |
类名::静态方法 |
2 | (参数1, 其他参数) -> 参数1.实例方法(其他参数) |
类名::实例方法 |
3 | (参数) -> 表达式.实例方法(参数) |
表达式::实例方法 |
2.2 Функциональные интерфейсы в Java API
API Java 8 предоставляет нам несколько функциональных интерфейсов, которые необходимо понимать. Поскольку интерфейсы могут определять методы по умолчанию, начиная с Java 8, эти интерфейсы предоставляют некоторые интересные методы по умолчанию. Это может быть полезно для нашего программирования.
public interface Predicate<T> {
boolean test(T t);
}
public interface Consumer<T> {
void accept(T t);
}
public interface Function<T, R> {
R apply(T t);
}
Выше приведено определение этих трех интерфейсов. Разница в сценариях их применения отражена в возвращаемых параметрах:
- Первый используется для суждения, которое грубо используется для достижения эффекта фильтрации;
- Во-вторых, нет возвращаемого типа, и его можно использовать только для обработки входящих параметров;
- Третий — для отображения, то есть его можно использовать, когда параметр и возвращаемое поведение, которое вы хотите реализовать, имеют разные типы (конечно, если они одного типа).
Потому что для числовых типов в Java необходимо выполнять дополнительные операции упаковки и распаковки, за которые приходится платить. Поэтому для трех вышеуказанных интерфейсов (другие интерфейсы тоже есть) в Java8 предусмотрена версия, не требующая упаковки, то есть от дженериков к числовым типам. Возьмите IntPredicate в качестве примера:
public interface IntPredicate {
boolean test(int value);
}
2.3 Составные лямбда-выражения
Некоторые из интерфейсов, представленных в Java8, все еще могут быть составными. Более сложная логика может быть реализована с помощью составных операций. Эти составные операции определены как методы по умолчанию, каждая из которых имеет немного отличающийся функциональный интерфейс. Поэтому мы перечислим здесь только некоторые методы, используемые для композиции. В реальном процессе разработки вы можете напрямую войти в указанный функциональный интерфейс для просмотра определений этих методов.
2.3.1 Компаратор
Предположим, есть список сотрудников, объектом которого является Employee, и у него есть два метода: getName() и getAge().
employees.sort(Comparator.comparing(Employee::getName));
employees.sort(Comparator.comparing(Employee::getName).reversed().thenComparing(Employee::getAge));
В приведенных выше двух строках кода первая строка реализует сортировку сотрудников в соответствии с результатом getName(). Вторая строка кода сортирует сотрудников в соответствии с результатами getName(), затем переворачивает возвращенные результаты, а затем сортирует их в соответствии с результатами getAge().
2.3.2 Составные предикаты negate(), or() и and()
Predicate<Employee> employeePredicate = (employee -> employee.getAge() > 13)
employeePredicate.negate()
employeePredicate.and(employee -> employee.getAge() <= 15).or(employee -> "LiHua".equals(employee.getName()))
Сначала здесь определяется employeePredicate, который можно использовать для фильтрации «сотрудников, чей возраст старше 13 лет». Вызов метода negate() вернет предикат, который можно использовать для фильтрации «сотрудников, чей возраст меньше или равен 13». Последняя составная операция означает «сотрудников, возраст которых больше 13 и меньше 15 лет, или сотрудника по имени ЛиХуа».
Обратите внимание, что порядок операций и и или здесь слева направо, то естьa.or(b).and(c)
будет рассматриваться как(a || b) and c
.
2.3.3 Функциональный состав
У функции есть два метода по умолчанию: andThen и compose, оба из которых возвращают экземпляр функции.
Function<Integer, Integer> f = x -> x + 1;
Function<Integer, Integer> g = x -> x * 2;
Function<Integer, Integer> h1 = f.andThen(g); // h1(x) = g(f(x)) = (x + 1) * 2
Function<Integer, Integer> h2 = f.compose(g); // h2(x) = f(g(x)) = (x * 2) + 1
System.out.println(h1.apply(1));
System.out.println(h2.apply(1));
Вышеприведенный пример составной операции Function фактически эквивалентен составной функции в математике. Однако следует отметить, что фактическое комбинированное действие двух методов различно.
Суммировать
Вышеизложенное является первой частью улучшения Java 8. Подводя итог: параметризация поведения на самом деле является шаблоном стратегии. Использование Lambda может упростить форму функциональных интерфейсов; Java API предоставляет некоторые полезные функциональные интерфейсы, которые могут быть более мощными при использовании составных методов. , функция.