Transcript
Page 1: Discovering Lambdas in Java 8

Discovering Lambdas in Java8

by Aleksandra Dmytrenko

Page 2: Discovering Lambdas in Java 8

План

Старая добрая Java -> Функциональное программирование

Как посчитать факториал?

Слон и моська в одном

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

Page 3: Discovering Lambdas in Java 8

Функциональное

программирование!

Page 4: Discovering Lambdas in Java 8

Чем ФП приятно?

Функция не может поменять значение переменной вне своей видимости, все

переменные final (рай для юнит тестов)

Внешние состояние не влияет на функцию (удобно отлаживать и замещать части

кода).

Встроенная многопоточность (кому нравится думать про «разделяй и

властвуй?»)

Ленивые (отложенные) вычисления - выполняется только нужный код в момент,

когда надо результат.

Page 5: Discovering Lambdas in Java 8

Чем ФП чревато?

Состояние не хранится (нет переменных)

Все переменные final или const, нет public (как вам код с такими

ограничениями?)

Встроенная многопоточность (к сожалению пока не на высшем уровне)

Ленивые (отложенные) вычисления - выполняется только используемый код в

«когда захочу» момент. Тяжело контролировать очередность действий.

Page 6: Discovering Lambdas in Java 8

К делу

Page 7: Discovering Lambdas in Java 8

Как определить, простое ли число?

Page 8: Discovering Lambdas in Java 8

Легким движением руки

императивное

программиро-вание

превращается в

декларативное

Page 9: Discovering Lambdas in Java 8

КАК делаем -> ЧТО делаем?

Imperative style:

public boolean isPrime(int number) {

for (int curNumb = 2; curNumb <= number/2; curNumb++) {

if (number % curNumb == 0) {

return false;

}

}

return true;

}

DECLARATIVE STYLE:public boolean isPrimeDeclarative(final int number) { return IntStream.rangeClosed(2, number/2) .noneMatch(curNumb -> number % curNumb == 0);}

Page 10: Discovering Lambdas in Java 8

Добавим проверку на знак числа

public boolean isPrimeImperative(int number) {

if (number < 0) {

return false;

}

for (int curNumb = 2; curNumb <= number / 2; curNumb++) {

if (number % curNumb == 0) {

return false;

}

}

return true;

}

public boolean isPrimeDeclarativeNegativeNumbCheck(final int number) { return number >= 0 && IntStream.rangeClosed(2, number.2).noneMatch(curNumb -> number % curNumb == 0);}

Page 11: Discovering Lambdas in Java 8

Ну… надо бы еще на что-то

посмотреть

Page 12: Discovering Lambdas in Java 8

Кого на собеседовании не просили посчитать

факториал?

public static int factorialOf(int number) {

if (number >= 0) {

int factorial = 1;

for (int curNumb = 2; curNumb <= number; curNumb++){

factorial = factorial * curNumber;

}

return factorial;

} else throw new IllegalArgumentException("Factorial can be counted only of not negative numbers.");

}

6 строчек!

Page 13: Discovering Lambdas in Java 8

public static int factorialOf(int number) {

if (number > 0) return number*factorialOf(number-1);

if (number == 0) return 1;

else throw new IllegalArgumentException("Factorial can be counted only of not negative numbers.");

}

3 строчки!

Факториал через цикл каждый напишет. А

рекурсия во что обойдется?

public static int factorialOf(int number) { if (number >= 0) return IntStream.rangeClosed(2, number) .reduce(1, (accResult, curNumb) -> accResult * curNumb); else throw new IllegalArgumentException("Factorial can be counted only of not negative numbers.");}

3 строчки!

Page 14: Discovering Lambdas in Java 8

– Я и многие другие

“Не делайте что-то только потому, что вы можете это сделать.

Делайте красиво.”

Page 15: Discovering Lambdas in Java 8

Chuck Norris can do multiple inheritance in

Java

Page 16: Discovering Lambdas in Java 8

Я скажу вам больше, не

только он может. Вы тоже! С

помощью интерфейсов,

правда.

Page 17: Discovering Lambdas in Java 8

А что если бы Cлон был Моськой, а Моська Cлоном?

interface Elephant {

default String makeSound(String name) {

return name + ": Не злите меня!";

}

}

interface Dog {

default String makeSound(String name) {

return name + ": Гав-гав";

}

}

Page 18: Discovering Lambdas in Java 8

class EveryDogWantsToBeAnElephant implements Dog, Elephant {

@Override

public String makeSound(String name) {

return name + ": Я спокоен";

}

public static void main(final String[] args) {

EveryDogWantsToBeAnElephant elephantDog = new EveryDogWantsToBeAnElephant();

Elephant e = new Elephant(){};

Dog d = new Dog(){};

System.out.println(e.makeSound("Слон"));

System.out.println(d.makeSound("Моська"));

System.out.println(elephantDog.makeSound("Моська-слон"));

}}

А что если бы Cлон был Моськой, а Моська Cлоном?

Слон: Не злите меня!Моська: Гав-гавМоська-слон: Я спокоен

Page 19: Discovering Lambdas in Java 8

Множественное наследование - это когда есть дефолтная

реализация метода с одинаковым названием в каждом

интерфейсе.

А как себя будут вести статические и абстрактные методы?

Page 20: Discovering Lambdas in Java 8

Статические методы

К ним мы обращаемся как

НазваниеКласса.имяМетода. По сути эта

комбинация всегда уникальна и ее можно

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

interface Dog {

static String walk() { return "Я бегаю быстренько своими маленькими лапками.»; }}

interface Elephant {

static String walk() { return "Я большой и ступаю тихо но тяжело."; }}—————————————————————————————————————System.out.println(Elephant.walk());System.out.println(Dog.walk());

OUTPUT:

Я большой и ступаю тихо но тяжело.Я бегаю быстренько своими маленькими лапками.

Page 21: Discovering Lambdas in Java 8

Абстрактные методы

Когда мы инстанциируем абстрактный класс (интерфейс), то надо реализовать

все абстрактные методы.

Но если мы имплементируем интерфейсы с одинаковыми названиями методов,

достаточно описать только один из них.

Page 22: Discovering Lambdas in Java 8

Пример: Comparator с его int compare(T o1, T o2),

Comparable с его int compareTo(T o)

и другие

Интерфейс, у которого есть только один абстрактный метод

называется функциональным интерфейсом

Page 23: Discovering Lambdas in Java 8

1. Можно по-старинке:

Elephant e = new Elephant() {

@Override

public boolean isProud() {

return false;

}

};

2. Можно по-модному:

Elephant e = () -> { return false; };

3. А можно без лишних слов:

Elephant e = () -> false;

Реализуем функциональный интерфейс

Page 24: Discovering Lambdas in Java 8

interface Elephant {

boolean isProud();

}

interface Dog {

boolean isProud();

}

System.out.println("Слон горделив: " + e.isProud());

System.out.println("Моська горделива: " + d.isProud());

System.out.println("Моська-слон горделив: " + elephantDog.isProud());

OUTPUT:

Слон горделив: false

Моська горделива: true

Моська-слон горделив: false

Функциональный интерфейс вызываем точно

так же

Page 25: Discovering Lambdas in Java 8

Подробнее про

Page 26: Discovering Lambdas in Java 8

Предикаты

1. Обычный предикат:public Predicate<Integer> isGreaterThan2New() { return a -> a > 2;}Как это выглядело раньше:public boolean isGreaterThan2Old(Integer a) { return a > 2;}

2. Обычный би-предикат:public BiPredicate<Integer, Integer> isGreaterThanFunc() { return (a, b) -> a > b;}

Как это выглядело раньше:public boolean isGreaterThan(Integer a, Integer b) { return a > b;}

Всегда возвращают

булеан, реализуют

интерфейс с методом

boolean test(T t);

Если реализуется метод boolean test(T t), почему нигде нет этого

названия?

Page 27: Discovering Lambdas in Java 8

Подробнее про

Page 28: Discovering Lambdas in Java 8

Функции

1. Обычный предикат:public Function<Integer, Integer> multiplyFuncBy2() { return (a) -> a * 2;}Как это выглядело раньше:public Integer multiplyBy2(Integer a) { return a * 2;}

2. Обычный би-предикат:public BiFunction<Integer, Integer, Integer> multiplyFuncBy() { return (a, b) -> a * b;}Как это выглядело раньше:public Integer multiplyFuncBy(Integer a, Integer b) { return a * b;}

В отличие от предикатов,

возвращают тип, указанный

на последнем месте и

принимает типы, указанные

вначале

Page 29: Discovering Lambdas in Java 8

Как применяем предикаты

1. Обычный и би-предикат, аналогичные методы:boolean actual = p.isGreaterThan2New().test(4);boolean actual = p.isGreaterThan2Old(4);p.isGreaterThanNew().test(4, 8);p.isGreaterThanOld(4, 8);

2. Предикат и соответствующий метод в стриме:values.stream().filter(p.isGreaterThan2New( )).collect(Collectors.toList());List<Integer> actual = values.stream().filter(v -> p.isGreaterThan2(v)).collect(Collectors.toList());

Нету параметра. Стрим сам

передает.

Page 30: Discovering Lambdas in Java 8

Как применяем функции?

1. Обычная и би-функция, аналогичные методы:int actual = f.multiplyFuncBy2().apply(5);int actual = f.multiplyBy2(5);f.multiplyFuncBy().apply(5, 3);f.multiplyBy(5, 3);

2. Функция и соответствующий метод в стриме: values.stream().map(f.multiplyFuncBy2()).skip(2).limit(2).collect(Collectors.toList());List<Integer> actual = values.stream().map(v -> f.multiplyFuncBy().apply(v, 3)).skip(2).limit(2).collect(Collectors.toList());

Параметр передается через apply()

Page 31: Discovering Lambdas in Java 8

Подробнее про

Page 32: Discovering Lambdas in Java 8

Consumer - потребитель

1. Обычный void метод превращается в консьюмер:public <T> void useConsumer(T t){ System.out.print("Consumer says: " + t);}public <T> Consumer<T> useConsumerFunc(){ return (t) -> System.out.print("Consumer says: " + t);}

2. Разница в использовании:consumer.useConsumer("Hello ;)"); consumer.useConsumerFunc().accept("Hello ;)");

3. Использование консьюмера в стриме: Stream.of(1, 6).forEach(consumer.useConsumerFunc() .andThen(l -> System.out.print("\n")));OUTPUT:

Consumer says: 1Consumer says: 6

Page 33: Discovering Lambdas in Java 8

Подробнее про

Page 34: Discovering Lambdas in Java 8

Supplier - поставщик

1. 2 метода - обычный и поставщик    public String useSupplier() { return Thread.currentThread().getStackTrace()[1].getMethodName(); }

public Supplier<String> useSupplierFunc() { System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName()); return () -> Thread.currentThread().getStackTrace()[1].getMethodName(); }

Page 35: Discovering Lambdas in Java 8

Supplier - поставщик

1. Тесты:String actual = supplier.useSupplier();String actual = supplier.useSupplierFunc().get();Stream.of("1 ").forEach(n -> System.out.println(n + supplier.useSupplierFunc()));

2. Вывод:1) useSupplier2) useSupplierFunc lambda$useSupplierFunc$03) useSupplierFunc 1 lambdas.functionalInterface.MySupplier$$Lambda$1/1449621165@3d8c7aca

Page 36: Discovering Lambdas in Java 8

Это совсем не все, но

основное, что надо знать о

Java

Тут код с презентации и слайды

https://github.com/olexandra-dmytrenko/LambdasForConfs.git

Page 37: Discovering Lambdas in Java 8

Спасибо за внимание :)