Презентация на тему: Лекция 7 Лямбда

Лекция 7 Лямбда
Пример
Пример
Пример
Лямбда выражение
Части лямбда выражения
Правила написания списка параметров лямбда выражений
Правила написания списка параметров лямбда выражений
Правила написания списка параметров лямбда выражений
Правила написания тела лямбда выражений
Правила написания тела лямбда выражений
Правила написания тела лямбда выражений
Функциональный интерфейс
Лямбда и интерфейс
Лямбда и интерфейс
Функциональный интерфейс
Пример 1 функционального интерфейса
Пример 2 функционального интерфейса
Пример 3 функционального интерфейса
Аннотация @ FunctionalInterface
Примеры функциональных интерфейсов
Лямбда и анонимные классы
Лямбда и анонимные классы
Встроенные функциональные интерфейсы
Функциональный интерфейс Predicate<T>
Функциональный дескриптор Predicate<T> интерфейса
Пример использования интерфейса Predicate<T>
Методы по умолчанию интерфейса Predicate
Методы по умолчанию интерфейса Predicate
Функциональный интерфейс Consumer<T>
Пример использования интерфейса Consumer<T>
Функциональный дескриптор интерфейса Consumer<T>
Метод andThen интерфейса Consumer
Пример использования интерфейса Consumer<T>
Функциональный интерфейс Function<T, R>
Функциональный дескриптор интерфейса Function<T, R>
Пример использования интерфейса Function<T,R>
Методы по умолчанию интерфейса Function<T,R>
Пример использования интерфейса Function<T,R>
Статический метод интерфейса Function<T,R>
Функциональный интерфейс Supplier<T>
Функциональный дескриптор интерфейса Supplier<T>
Пример использования интерфейса Supplier<T>
Встроенные функциональные интерфейсы
Функциональный интерфейс UnaryOperator
Функциональный дескриптор интерфейса UnaryOperator
Пример использования интерфейса UnaryOperator
Бинарные специализации
Примитивные специализации Predicate
Примитивные специализации Consumer
Примитивные специализации Function
Примитивные специализации Function
Примитивные специализации Supplier
Примитивные специализации UnaryOperator
Примитивные специализации BinaryOperator
Примитивные специализации BiConsumer
Примитивные специализации BiFunction
Ссылки на методы ( Method References )
Method References
1. Ссылка на статический метод
2. Ссылка на нестатический метод конкретного объекта
2. Ссылка на нестатический метод конкретного объекта
2. Ссылка на нестатический метод конкретного объекта
3. Ссылка на нестатический метод любого объекта конкретного типа
4. Ссылка на конструктор
4. Ссылка на конструктор
1/66
Средняя оценка: 4.5/5 (всего оценок: 66)
Код скопирован в буфер обмена
Скачать (307 Кб)
1

Первый слайд презентации: Лекция 7 Лямбда

Изображение слайда
2

Слайд 2: Пример

private int getCompactCarsNumber ( Car [] cars ) { int result = 0 ; for ( Car car : cars ) { if ( car.getType (). equals ( CarTypes. COMPACT )) { result ++; } } return result ; } private int getExpensiveCarsNumber ( Car [] cars ) { int result = 0 ; for ( Car car : cars ) { if ( car.getCost () > 20000) { result ++; } } return result ; } (CarDemo1.java)

Изображение слайда
3

Слайд 3: Пример

public interface Searchable { boolean test ( Car car ); } public class CompactCarSearch implements Searchable { public boolean test ( Car car ) { return car.getType (). equals ( CarTypes. COMPACT ); } } public class ExpensiveCarSearch implements Searchable { public boolean test ( Car car ) { return car.getCost () > 20000 ; } }

Изображение слайда
4

Слайд 4: Пример

private int getCarsNumber ( Car [] cars, Searchable s) { int result = 0 ; for ( Car car : cars ) { if ( s.test ( car )) { result ++; } } return result ; } private int getCompactCarsNumber ( Car [] cars ) { int result = 0 ; for ( Car car : cars ) { if ( car.getType (). equals ( CarTypes. COMPACT )) { result ++; } } return result ; } private int getExpensiveCarsNumber ( Car [] cars ) { int result = 0 ; for ( Car car : cars ) { if ( car.getCost () > 20000) { result ++; } } return result ; } (CarDemo1.java) carDemo.getCarsNumber ( cars, new CompactCarSearch ()); carDemo.getCarsNumber ( cars, new ExpensiveCarSearch ());

Изображение слайда
5

Слайд 5: Лямбда выражение

Вместо можно: carDemo.getCarsNumber ( cars, new Searchable () { @ Override public boolean test ( Car car ) { return car.getType (). equals ( CarTypes. COMPACT ); } }); carDemo.getCarsNumber ( cars, car -> car.getType (). equals ( CarTypes. COMPACT ));

Изображение слайда
6

Слайд 6: Части лямбда выражения

Синтаксис: ( параметры ) -> ( тело ) Пример: (Object arg1, Object arg2) -> arg1.equals(arg2); Лямбда выражение содержит три части: список параметров ; стрелочка ; тело.

Изображение слайда
7

Слайд 7: Правила написания списка параметров лямбда выражений

Лямбда выражение может содержать ноль и более входных параметров: ( int a1, int a2) -> { return a1 - a2; } (String s) -> { System.out.println (s); } () -> 89 ;

Изображение слайда
8

Слайд 8: Правила написания списка параметров лямбда выражений

Тип параметра может быть явно объявлен или выведен компилятором из значения параметра. Например: (String s) -> { System.out.println (s); } Можно переписать так: (s) -> { System.out.println (s); }

Изображение слайда
9

Слайд 9: Правила написания списка параметров лямбда выражений

Если параметров нет или их больше одного, скобки необходимы: (a1, a2) -> return a1 + a2; ( int a1, int a2) -> return a1 + a2; () -> 42; Нет необходимости объявлять один параметр в скобках, но в этом случае нельзя явно указать тип параметра: a1 -> return 2 * a1

Изображение слайда
10

Слайд 10: Правила написания тела лямбда выражений

Тело лямбда выражения может содержать одно и более выражений. Нет необходимости использовать фигурные скобки и ключевое слово return, если тело состоит из одного выражения. () -> 4; ( int  a) -> a*6;

Изображение слайда
11

Слайд 11: Правила написания тела лямбда выражений

Если тело содержит более одного выражения, фигурные скобки и ключевое слово return необходимы. () -> {       System.out.println ("Hi");      return 4; } ( int  a) -> {       System.out.println (a);      return a*6; }

Изображение слайда
12

Слайд 12: Правила написания тела лямбда выражений

Если ключевое слово return отсутствует, возвращаемый тип может быть void. () -> System.out.println ("Hi"); () -> {       System.out.println ("Hi");      return; }

Изображение слайда
13

Слайд 13: Функциональный интерфейс

Чтобы иметь возможность использовать лямбда выражения, необходим интерфейс. public interface Searchable { boolean test(Car car ); } Searchable s = (Car c) -> c.getCostUSD () > 20000;

Изображение слайда
14

Слайд 14: Лямбда и интерфейс

Лямбда выражения не содержат информацию о том, какой функциональный интерфейс они реализуют. Тип выражения выводится из контекста, в котором используется лямбда выражение. Этот тип называется целевой тип ( target type ). Если лямбда выражение присваивается какому-то интерфейсу, лямбда выражение должно соответствовать синтаксису метода интерфейса.

Изображение слайда
15

Слайд 15: Лямбда и интерфейс

Одно и то же лямбда выражение может использоваться с разными интерфейсами, если они имеют абстрактные методы, которые совместимы. interface Searchable {       boolean  test(Car car ); } interface Saleable {       boolean  approve(Car car ); } //... Searchable s1 = c -> c.getCostUSD () > 20000; Saleable s2 = c -> c.getCostUSD () > 20000;

Изображение слайда
16

Слайд 16: Функциональный интерфейс

Функциональный интерфейс ( functional interface ) – это интерфейс у которого только один абстрактный метод. Функциональный интерфейс может содержать любое количество методов по умолчанию ( default ) или статических методов.

Изображение слайда
17

Слайд 17: Пример 1 функционального интерфейса

interface A {      default  int   defaultMethod () {          return 0;      }      void method(); }

Изображение слайда
18

Слайд 18: Пример 2 функционального интерфейса

interface B {      default  int   defaultMethod () {          return 0;      }      default  int   anotherDefaultMethod () {          return 0;      }      void method(); }

Изображение слайда
19

Слайд 19: Пример 3 функционального интерфейса

interface A {       boolean  equals(Object o);       int   hashCode ();      String  toString ();      void method(); }

Изображение слайда
20

Слайд 20: Аннотация @ FunctionalInterface

В Java 8 была введена аннотация @ FunctionalInterface, которая генерирует ошибку компиляции, если интерфейс не является функциональным. // This won't compile @ FunctionalInterface interface A {      void m( int   i );      void m(long l); }

Изображение слайда
21

Слайд 21: Примеры функциональных интерфейсов

java.lang.Runnable java.util.Comparator

Изображение слайда
22

Слайд 22: Лямбда и анонимные классы

Лямбда выражения являются альтернативой анонимным классам. Но они не одинаковы. Общее: Локальные переменные могут быть использованы только если они final или effective final. Разрешается доступ к переменным класса и статическим переменным класса. Они не должны выбрасывать больше исключений чем определено в throws метода функционального интерфейса.

Изображение слайда
23

Слайд 23: Лямбда и анонимные классы

Различия : Для анонимных классов ключевое слово this ссылается на сам класс. Для лямбда выражений на внешний класс. Анонимные классы компилируются во внутренние классы. Но лямбда выражения преобразуются в статические private методы класса, в котором они используют invokedynamic инструкцию. Лямбда более эффективны, т.к. не надо загружать еще один класс.

Изображение слайда
24

Слайд 24: Встроенные функциональные интерфейсы

В Java 8 добавлены встроенные функциональные интерфейсы в пакет java.util.function : Predicate Consumer Function Supplier UnaryOperator

Изображение слайда
25

Слайд 25: Функциональный интерфейс Predicate<T>

Принимает на вход значение, проверяет состояние и возвращает boolean значение в качестве результата. Predicate<T> “ подтверждает ” какое-то значение как true или false. @ FunctionalInterface public interface Predicate<T> { boolean test(T t ); }

Изображение слайда
26

Слайд 26: Функциональный дескриптор Predicate<T> интерфейса

T -> boolean

Изображение слайда
27

Слайд 27: Пример использования интерфейса Predicate<T>

public class PredicateDemo1 { public static void main ( String [] args ) { Predicate < Integer > negative = i -> i < 0 ; System. out.println ( negative.test (- 6 )); System. out.println ( negative.test ( 6 )); System. out.println ( negative.test ( 0 )); } }

Изображение слайда
28

Слайд 28: Методы по умолчанию интерфейса Predicate

Predicate интерфейс содержит методы по умолчанию : default Predicate<T> and(Predicate<? super T> other); default Predicate<T> or(Predicate<? super T> other); default Predicate<T> negate();

Изображение слайда
29

Слайд 29: Методы по умолчанию интерфейса Predicate

public class PredicateDemo2 { public static void main ( String [] args ) { Predicate < String > containsA = t -> t.contains ( "A" ); Predicate < String > containsB = t -> t.contains ( "B" ); System. out.println ( containsA.and ( containsB ). test ( "ABCD" )); } }

Изображение слайда
30

Слайд 30: Функциональный интерфейс Consumer<T>

Принимает значение в качестве аргумента и ничего не возвращает. @ FunctionalInterface public interface Consumer<T> { void accept(T t ); }

Изображение слайда
31

Слайд 31: Пример использования интерфейса Consumer<T>

public class ConsumerDemo1 { public static void main ( String [] args ) { Consumer < String > printUpperCase = str -> System. out.println ( str.toUpperCase ()); printUpperCase.accept ( " hello " ); Consumer < String > printLowerCase = str -> System. out.println ( str.toLowerCase ()); } }

Изображение слайда
32

Слайд 32: Функциональный дескриптор интерфейса Consumer<T>

T -> void

Изображение слайда
33

Слайд 33: Метод andThen интерфейса Consumer

Consumer интерфейс содержит метод по умолчанию, который возвращает составной Consumer, выполняющий последовательно действия указанные в каждом интерфейсе. default Consumer<T> andThen (Consumer<? super T> after)

Изображение слайда
34

Слайд 34: Пример использования интерфейса Consumer<T>

public class ConsumerDemo1 { public static void main ( String [] args ) { Consumer < String > printUpperCase = str -> System. out.println ( str.toUpperCase ()); printUpperCase.accept ( " hello " ); Consumer < String > printLowerCase = str -> System. out.println ( str.toLowerCase ()); printUpperCase.andThen ( printLowerCase ). accept ( " Hello world " ); } }

Изображение слайда
35

Слайд 35: Функциональный интерфейс Function<T, R>

Принимает значение в качестве аргумента одного типа и возвращает другое значение. Часто используется для преобразования одного значения в другое. @ FunctionalInterface public interface Function<T, R> { R apply(T t ); }

Изображение слайда
36

Слайд 36: Функциональный дескриптор интерфейса Function<T, R>

T -> R

Изображение слайда
37

Слайд 37: Пример использования интерфейса Function<T,R>

public class FunctionDemo1 { public static void main ( String [] args ) { Function < Double, Long > function = d -> Math. round (d); System. out.println ( function.apply ( 5.7 )); } }

Изображение слайда
38

Слайд 38: Методы по умолчанию интерфейса Function<T,R>

default <V> Function<T, V> andThen (Function<? super R, ? extends V> after); default <V> Function<V, R> compose(Function<? super V, ? extends T> before);

Изображение слайда
39

Слайд 39: Пример использования интерфейса Function<T,R>

public class FunctionDemo2 { public static void main ( String [] args ) { Function < String, String > f1 = s -> s + "1" ; Function < String, String > f2 = s -> s + "2" ; Function < String, String > f3 = s -> s + "3" ; Function < String, String > f4 = s -> s + "4" ; System. out.println (f1.andThen(f2). compose (f3). compose (f4). apply ( " Compose " )); System. out.println (f1.andThen(f2). andThen (f3). apply ( " AndThen " )); } }

Изображение слайда
40

Слайд 40: Статический метод интерфейса Function<T,R>

static <T> Function<T, T> identity() Возвращает интерфейс Function, который всегда возвращает входной параметр. Пример: public class FunctionDemo3 { public static void main ( String [] args ) { Function < String, String > f = Function. identity (); System. out.println ( f.apply ( " Some Value " )); } }

Изображение слайда
41

Слайд 41: Функциональный интерфейс Supplier<T>

Возвращает значение, одно и тоже или разные. @ FunctionalInterface public interface Supplier<T> { T get(); }

Изображение слайда
42

Слайд 42: Функциональный дескриптор интерфейса Supplier<T>

() -> T

Изображение слайда
43

Слайд 43: Пример использования интерфейса Supplier<T>

public class SupplierDemo1 { public static void main ( String [] args ) { String t = " One " ; Supplier < String > supplierStr = () -> t.toUpperCase (); System. out.println ( supplierStr.get ()); } }

Изображение слайда
44

Слайд 44: Встроенные функциональные интерфейсы

Изображение слайда
45

Слайд 45: Функциональный интерфейс UnaryOperator

UnaryOperator расширяет интерфейс Function. Используется в случае, если аргумент и возвращаемое значение одного типа. @ FunctionalInterface public interface UnaryOperator <T> extends Function<T, T> { … }

Изображение слайда
46

Слайд 46: Функциональный дескриптор интерфейса UnaryOperator

T -> T

Изображение слайда
47

Слайд 47: Пример использования интерфейса UnaryOperator

public class UnaryOperatorDemo { public static void main ( String [] args ) { UnaryOperator < String > uo = s -> s.toUpperCase (); System. out.print ( uo.apply ( " Java 12" )); } }

Изображение слайда
48

Слайд 48: Бинарные специализации

Существуют бинарные специализации ( binary specializations ) функций Predicate, Consumer, Function и UnaryOperator, которые принимают на вход два элемента. BiConsumer <T, U> BiFunction <T, U, R> BiPredicate <T, U> BinaryOperator <T>

Изображение слайда
49

Слайд 49: Примитивные специализации Predicate

Интерфейс Описание IntPredicate Принимает на вход значение типа int возвращает значение типа boolean. LongPredicate Принимает на вход значение типа long возвращает значение типа boolean. DoublePredicate Принимает на вход значение типа double возвращает значение типа boolean.

Изображение слайда
50

Слайд 50: Примитивные специализации Consumer

Интерфейс Описание IntConsumer Принимает на вход значение типа int и ничего не возвращает. LongConsumer Принимает на вход значение типа long и ничего не возвращает. DoubleConsumer Принимает на вход значение типа double и ничего не возвращает.

Изображение слайда
51

Слайд 51: Примитивные специализации Function

Интерфейс Описание IntFunction <R> Принимает на вход значение типа int и возвращает значение типа R. LongFunction <R> Принимает на вход значение типа long и возвращает значение типа R. DoubleFunction <R> Принимает на вход значение типа double и возвращает значение R. Интерфейс Описание ToIntFunction <T> Принимает на вход значение типа T и возвращает значение типа int. ToDoubleFunction <T> Принимает на вход значение типа T и возвращает значение типа double. ToLongFunction <T> Принимает на вход значение типа T и возвращает значение типа long.

Изображение слайда
52

Слайд 52: Примитивные специализации Function

Интерфейс Описание IntToDoubleFunction Принимает на вход значение типа int и возвращает значение типа double. IntToLongFunction Принимает на вход значение типа int и возвращает значение типа long. LongToDoubleFunction Принимает на вход значение типа long и возвращает значение типа double. LongToIntFunction Принимает на вход значение типа long и возвращает значение типа int. DoubleToIntFunction Принимает на вход значение типа double и возвращает значение типа int. DoubleToLongFunction Принимает на вход значение типа double и возвращает значение типа long.

Изображение слайда
53

Слайд 53: Примитивные специализации Supplier

Интерфейс Описание BooleanSupplier Возвращает значение типа boolean. IntSupplier Возвращает значение типа int. LongSupplier Возвращает значение типа   long. DoubleSupplier Возвращает значение типа double.

Изображение слайда
54

Слайд 54: Примитивные специализации UnaryOperator

Интерфейс Описание IntUnaryOperator Принимает и возвращает значение типа int. LongUnaryOperator Принимает и возвращает значение типа long. DoubleUnaryOperator Принимает и возвращает значение типа double.

Изображение слайда
55

Слайд 55: Примитивные специализации BinaryOperator

Интерфейс Описание IntBinaryOperator Принимает на вход два значения типа int и возвращает значение типа int. LongBinaryOperator Принимает на вход два значения типа long и возвращает значение типа long. DoubleBinaryOperator Принимает на вход два значения типа double и возвращает значение типа double.

Изображение слайда
56

Слайд 56: Примитивные специализации BiConsumer

Интерфейс Описание ObjIntConsumer <T> Принимает на вход два значения : типа int и Object. ObjLongConsumer <T> Принимает на вход два значения : типа long и Object. ObjDoubleConsumer <T > Принимает на вход два значения : типа double и Object.

Изображение слайда
57

Слайд 57: Примитивные специализации BiFunction

Интерфейс Описание ToIntBiFunction <T, U> Принимает на вход два объекта и возвращает значение типа int. ToLongBiFunction <T, U> Принимает на вход два объекта и возвращает значение типа long. ToDoubleBiFunction <T, U> Принимает на вход два объекта и возвращает значение типа double.

Изображение слайда
58

Слайд 58: Ссылки на методы ( Method References )

Если лямбда выражения вызывают только один существующий метод, лучше ссылать на этот метод по его имени. Method References – это компактные лямбда выражения для методов у которых уже есть имя. Например: Consumer<String> consumer = str -> System.out.println ( str ); Можно переписать с помощью Method References: Consumer<String> consumer = System.out :: println ;

Изображение слайда
59

Слайд 59: Method References

Тип Пример Ссылка на статический метод ContainingClass :: staticMethodName Ссылка на нестатический метод конкретного объекта containingObject :: instanceMethodName Ссылка на нестатический метод любого объекта конкретного типа ContainingType :: methodName Ссылка на конструктор ClassName ::new

Изображение слайда
60

Слайд 60: 1. Ссылка на статический метод

Синтаксис: ContainingClass :: staticMethodName Например: Function<String, Boolean> function = e -> Boolean.valueOf (e); System.out.println ( function.apply ("TRUE")); Перепишем с помощью ссылки: Function<String, Boolean> function = Boolean:: valueOf ; System.out.println ( function.apply ("TRUE"));

Изображение слайда
61

Слайд 61: 2. Ссылка на нестатический метод конкретного объекта

Синтаксис: containingObject :: instanceMethodName Этот тип используется когда лямбда выражение вызывает метод внешнего уже существующего объекта.

Изображение слайда
62

Слайд 62: 2. Ссылка на нестатический метод конкретного объекта

Например: Consumer<String> consumer = e -> System.out.println (e); consumer.accept ("OCPJP 8"); Перепишем, используя ссылку: Consumer<String> consumer = System.out :: println ; consumer.accept ("OCPJP 8");

Изображение слайда
63

Слайд 63: 2. Ссылка на нестатический метод конкретного объекта

Пример: Integer integer = 5; Supplier<String> supplier = () -> integer.toString (); System.out.println ( supplier.get ()); Перепишем: Integer integer = 5; Supplier<String> supplier = integer:: toString ; System.out.println ( supplier.get ());

Изображение слайда
64

Слайд 64: 3. Ссылка на нестатический метод любого объекта конкретного типа

Синтаксис : ContainingType :: methodName Например: Function<String, String> function = s -> s.toLowerCase (); System.out.println ( function.apply ("OCPJP 8")); Перепишем: Function<String, String> function = String:: toLowerCase ; System.out.println ( function.apply ("OCPJP 8"));

Изображение слайда
65

Слайд 65: 4. Ссылка на конструктор

Синтаксис: ClassName ::new ClassName не может быть абстрактным классом или интерфейсом.

Изображение слайда
66

Последний слайд презентации: Лекция 7 Лямбда: 4. Ссылка на конструктор

Например: Function<String, Integer> function = (d) -> new Integer(d); System.out.println ( function.apply ("4")); Перепишем: Function<String, Integer> function = Integer::new; System.out.println ( function.apply ("4"));

Изображение слайда