Discovering Lambdas (Speech)

Post on 14-Feb-2017

52 views 0 download

Transcript of Discovering Lambdas (Speech)

Discovering Lambdas in Discovering Lambdas in Java8Java8

by Aleksandra Dmytrenkoby Aleksandra Dmytrenko

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

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

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

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

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

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

Чем ФП приятно?Чем ФП приятно?Функция не может поменять значение переменной вне своей видимости, все переменные final (рай для юнит тестов)

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

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

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

Чем ФП чревато?Чем ФП чревато?Состояние не хранится (нет переменных)

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

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

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

К делуК делу

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

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

руки руки императивное императивное программиро-программиро-

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

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

ее

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

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);}

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

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);}

Ну… надо бы еще на Ну… надо бы еще на что-то посмотретьчто-то посмотреть

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

факториал?факториал?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 строчек!

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 строчки!

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

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

красиво.”

Chuck Norris can do Chuck Norris can do multiple inheritance in multiple inheritance in

JavaJava

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

может. Вы тоже! может. Вы тоже! С помощью С помощью

интерфейсов, интерфейсов, правда.правда.

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

interface Elephant { default String makeSound(String name) { return name + ": Не злите меня!"; }}

interface Dog { default String makeSound(String name) { return name + ": Гав-гав"; }}

class EveryDogWantsToBeAnElephant implements Dog, Elephant {@Overridepublic 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лон был Моськой, а Моська Cлоном?Моська Cлоном?

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

Множественное наследование - это когда есть дефолтная реализация метода с одинаковым названием в

каждом интерфейсе.А как себя будут вести статические и

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

Статические методыСтатические методыК ним мы обращаемся как НазваниеКласса.имяМетода. По сути эта комбинация всегда уникальна и ее можно воспринимать целиком, как название

interface Dog {

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

interface Elephant {

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

OUTPUT:

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

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

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

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

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

и другие

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

1. Можно по-старинке:Elephant e = new Elephant() { @Override public boolean isProud() { return false; }};

2. Можно по-модному:Elephant e = () -> { return false; };

3. А можно без лишних слов:Elephant e = () -> false;

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

интерфейсинтерфейс

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

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

точно так жеточно так же

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

ПредикатыПредикаты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 boolean testtest((T T t)t);;

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

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

ФункцииФункции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;}

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

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

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

типы, указанные типы, указанные вначалевначале

Как применяем Как применяем предикатыпредикаты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());

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

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

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()apply()

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

Consumer - 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

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

Supplier - поставщик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(); }

Supplier - поставщик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

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

JavaJava

Тут код с презентации и слайдыhttps://github.com/olexandra-dmytrenko/LambdasForConfs.git

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