Главная страница
Навигация по странице:

  • 1. Что такое функциональный интерфейс Примеры 2. Для чего нужна аннотация @FunctionalInterface 3. Какие встроенные функциональные интерфейсы вы знаете

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

  • 5. Что такое лямбда-выражение Чем его можно заменить

  • 10. Stream API 1. Что такое Stream API Для чего нужны стримы

  • 2. Почему Stream называют ленивым

  • 3. Какие существуют способы создания стрима

  • 4. Как из коллекции создать стрим

  • 7. Расскажите про метод map() “маппинг – из одного в другое”.

  • 8. Расскажите про метод flatMap(). “плоский маппинг”

  • 9. Чем отличаются методы map() и flatMap(). 10. Расскажите про метод filter()

  • 11. Расскажите про метод limit()

  • 12. Расскажите про метод skip()

  • 14. Расскажите про метод distinct() “особый”

  • 15. Какие терминальные методы в стримах вы знаете

  • 16. Расскажите про метод collect() “собирать”

  • 17. Расскажите про метод reduce() “уменьшить”

  • 18. Расскажите про класс Collectors и его методы.

  • 1. Что такое дженерики


    Скачать 0.84 Mb.
    Название1. Что такое дженерики
    АнкорCore-2
    Дата23.03.2022
    Размер0.84 Mb.
    Формат файлаpdf
    Имя файла02_CORE_2-1.pdf
    ТипДокументы
    #410542
    страница4 из 5
    1   2   3   4   5
    41. Какое худшее время работы метода get(key) для ключа, которого нет в HashMap?
    42. Какое худшее время работы метода get(key) для ключа, который есть в HashMap?
    O(N). Худший случай - это поиск ключа в HashMap, вырожденного в список по причине совпадения ключей по hashCode() и для выяснения хранится ли элемент с определённым ключом может потребоваться перебор всего списка.
    9. Функциональные интерфейсы
    1. Что такое функциональный интерфейс? Примеры
    2. Для чего нужна аннотация @FunctionalInterface?
    3. Какие встроенные функциональные интерфейсы вы знаете?
    Функциональный интерфейс - это интерфейс, который определяет только один абстрактный метод.
    Основное назначение – использование в лямбда выражениях и method reference.
    Чтобы точно определить интерфейс как функциональный, добавлена аннотация @FunctionalInterface, работающая по принципу @Override. Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.
    Интерфейс может включать сколько угодно default методов и при этом оставаться функциональным, потому что default методы - не абстрактные. встроенные функциональные интерфейсы:
    - Predicate Проверяет соблюдение некоторого условия. Если оно соблюдается, то возвращается значение true. В качестве параметра лямбда-выражение принимает объект типа T
    - Consumer выполняет некоторое действие над объектом типа T, при этом ничего не возвращая
    - Function представляет функцию перехода от объекта типа T к объекту типа R
    - Supplier не принимает никаких аргументов, но должен возвращать объект типа T
    - UnaryOperator принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T
    - BinaryOperator принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T
    Predicate public interface Predicate { boolean test(T t); import java.util.function.Predicate;

    } public class LambdaApp { public static void main(String[] args) {
    Predicate isPositive = x -> x > 0;
    System.out.println(isPositive.test(5)); // true
    System.out.println(isPositive.test(-7)); // false
    }
    }
    BinaryOperator public interface
    BinaryOperator {
    T apply(T t1, T t2);
    } import java.util.function.BinaryOperator; public class LambdaApp { public static void main(String[] args) {
    BinaryOperator multiply = (x, y) -> x*y;
    System.out.println(multiply.apply(3, 5)); // 15
    System.out.println(multiply.apply(10, -2)); // -20
    }
    }
    UnaryOperator public interface
    UnaryOperator {
    T apply(T t);
    } import java.util.function.UnaryOperator; public class LambdaApp { public static void main(String[] args) {
    UnaryOperator square = x -> x*x;
    System.out.println(square.apply(5)); // 25
    }
    }
    Function public interface Function {
    R apply(T t);
    } import java.util.function.Function; public class LambdaApp { public static void main(String[] args) {
    Function convert = x-> String.valueOf(x)
    + " долларов";
    System.out.println(convert.apply(5)); // 5 долларов
    }
    }
    Consumer public interface Consumer { void accept(T t);
    } import java.util.function.Consumer; public class LambdaApp { public static void main(String[] args) {
    Consumer printer = x-> System.out.printf("%d долларов \n", x); printer.accept(600); // 600 долларов
    }
    }
    Supplier public interface Supplier {
    T get();
    } import java.util.Scanner; import java.util.function.Supplier; public class LambdaApp { public static void main(String[] args) {
    Supplier userFactory = ()->{
    Scanner in = new Scanner(System.in);
    System.out.println("Введите имя: ");
    String name = in.nextLine(); return new User(name);
    };
    User user1 = userFactory.get();
    User user2 = userFactory.get();
    System.out.println("Имя user1: " + user1.getName());
    System.out.println("Имя user2: " + user2.getName());
    }
    Введите имя:
    Том
    Введите имя:
    Сэм
    Имя user1: Том
    Имя user2: Сэм

    4. Что такое ссылка на метод?
    Ссылки на методы (Method References) – это компактные лямбда выражения для методов, у которых уже есть имя.
    Ссылки на методы бывают четырех видов:
    - Ссылка на статический метод - ContainingClass::staticMethodName
    Function function = e -> Boolean.valueOf(e);
    System.out.println(function.apply("TRUE"));
    Function function = Boolean::valueOf;
    System.out.println(function.apply("TRUE"));,
    - Ссылка на нестатический метод конкретного объекта - containingObject::instanceMethodName
    Consumer consumer = e -> System.out.println(e); consumer.accept("OCPJP 8");
    Consumer consumer = System.out::println; consumer.accept("OCPJP 8");
    - Ссылка на нестатический метод любого объекта конкретного типа
    ContainingType::methodName
    Function function = s -> s.toLowerCase();
    System.out.println(function.apply("OCPJP 8"));
    Function function = String::toLowerCase;
    System.out.println(function.apply("OCPJP 8"));
    - Ссылка на конструктор ClassName::new
    Function function = (d) -> new Integer(d);
    System.out.println(function.apply("4"));
    Function function = Integer::new;
    System.out.println(function.apply("4"));
    5. Что такое лямбда-выражение? Чем его можно заменить?
    Представляет набор инструкций, которые можно выделить в отдельную переменную и затем многократно вызвать в различных местах программы.
    Образует реализацию метода, определенного в функциональном интерфейсе. При этом важно, что функциональный интерфейс должен содержать только один единственный метод без реализации. список параметров выражения -> тело лямбда-выражения (действия)
    Параметры лямбда-выражения должны соответствовать по типу параметрам метода из функционального интерфейса. в лямбда-выражении использование обобщений не допускается. В этом случае нам надо типизировать объект интерфейса определенным типом, который потом будет применяться в лямбда-выражении public class LambdaApp { public static void main(String[] args) {
    Operationable operation1 = (x, y)-> x + y;
    Operationable operation2 = (x, y) -> x + y;
    System.out.println(operation1.calculate(20, 10)); //30
    System.out.println(operation2.calculate("20", "10")); //2010
    }
    } interface Operationable{
    T calculate(T x, T y);

    }
    Одним из ключевых моментов в использовании лямбд является отложенное выполнение (deferred execution). То есть мы определяем в одном месте программы лямбда-выражение и затем можем его вызывать при необходимости неопределенное количество раз в различных частях программы. Отложенное выполнение может потребоваться, к примеру, в следующих случаях:
    Выполнение кода отдельном потоке
    Выполнение одного и того же кода несколько раз
    Выполнение кода в результате какого-то события
    Выполнение кода только в том случае, когда он действительно необходим и если он необходим
    10. Stream API
    1. Что такое Stream API? Для чего нужны стримы?
    Интерфейс java.util.Stream представляет собой последовательность элементов, над которой можно производить различные операции.
    Нужны для упрощения работы с наборами данных, в частности, упростить операции фильтрации, сортировки и другие манипуляции с данными.
    IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
    .limit(3).forEach(System.out::print);
    - создаем экземпляр Stream
    Пустой стрим: Stream.empty()
    Стрим из List: list.stream()
    Стрим из Map: map.entrySet().stream()
    Стрим из массива: Arrays.stream(array)
    Стрим из указанных элементов: Stream.of("1", "2", "3")
    Стрим из BufferedReader с помощью метода lines (); нужно закрывать close ().
    - Промежуточные (“intermediate”, “lazy”) — обрабатывают поступающие элементы и возвращают стрим.
    Может быть много, а может и не быть ни одной.
    - Терминальные (“terminal”, ещё называют “eager”) — обрабатывают элементы и завершают работу стрима, может быть только один.
    Важные моменты:
    - Обработка не начнётся до тех пор, пока не будет вызван терминальный оператор. list.stream().filter(s -
    > s > 5) (не возьмёт ни единого элемента из списка);
    - Экземпляр стрима нельзя использовать более одного раза;
    Коллекции
    Streams
    Конечны (хранят набор элементов)
    Бесконечны
    Индивидуальный доступ к элементам
    Нет индивид. доступа к элементам
    Можно менять (добавлять/удалять) элементы, в т.ч. через итератор
    Если как то обрабатываем данные, то не влияет на источник
    Кроме универсальных объектных существуют особые виды стримов для работы с примитивными типами данных int, long и double: IntStream, LongStream и DoubleStream. Эти примитивные стримы работают так же, как и обычные объектные, но со следующими отличиями:
    - используют специализированные лямбда-выражения, например, IntFunction или IntPredicate вместо
    Function и Predicate;

    - поддерживают дополнительные конечные операции sum(), average(), mapToObj()
    2. Почему Stream называют ленивым?
    Ленивое программирование -- технология, которая позволяет вам отсрочить вычисление кода до тех пор, пока не понадобится его результирующее значение.
    Блок обработки – промежуточные операции не выполняются, пока не вызовется терминальная.
    3. Какие существуют способы создания стрима?
    Из коллекции:
    Stream fromCollection = Arrays.asList("x", "y", "z").stream();
    Из набора значений:
    Stream fromValues = Stream.of("x", "y", "z");
    Из массива:
    Stream fromArray = Arrays.stream(new String[]{"x", "y", "z"});
    Из файла (каждая строка в файле будет отдельным элементом в стриме):
    Stream fromFile = Files.lines(Paths.get("input.txt"));
    Из строки:
    IntStream fromString = "0123456789".chars();
    С помощью Stream.builder():
    Stream fromBuilder = Stream.builder().add("z").add("y").add("z").build();
    С помощью Stream.iterate() (бесконечный):
    Stream fromIterate = Stream.iterate(1, n -> n + 1);
    С помощью Stream.generate() (бесконечный):
    Stream fromGenerate = Stream.generate(() -> "0");
    4. Как из коллекции создать стрим?
    Stream fromCollection = Arrays.asList("x", "y", "z").stream();
    5. Какие промежуточные методы в стримах вы знаете?
    6. Расскажите про метод peek() “быстрый взгляд”.
    - peek (принимает Consumer) integerStream.peek(System.out::println) позволяет подсмотреть какие элементы летают на данном этапе с помощью System.out::println
    Stream peek(Consumer action);
    7. Расскажите про метод map() “маппинг – из одного в другое”.
    Отображение или маппинг позволяет задать функцию преобразования одного объекта в другой, то есть получить из элемента одного типа элемент другого типа. принимает Function.
    Stream map(Function mapper); map(n -> n.toString())
    8. Расскажите про метод flatMap(). “плоский маппинг”
    Плоское отображение выполняется тогда, когда из одного элемента нужно получить несколько.
    Stream
    .of("H e l l o", "w o r l d !")
    .flatMap((p) -> Arrays.stream(p.split(" ")))
    .toArray(String[]::new);//["H", "e", "l", "l", "o", "w", "o", "r", "l", "d", "!"]
    Например, в примере выше мы выводим название телефона и его цену. Но что, если мы хотим установить для каждого телефона цену со скидкой и цену без скидки. То есть из одного объекта
    Phone нам надо получить два объекта с информацией, например, в виде строки. Для этого применим flatMap:
    Stream phoneStream = Stream.of(new Phone("iPhone 6 S", 54000), new Phone("Lumia 950",
    45000),
    new Phone("Samsung Galaxy S 6", 40000)); phoneStream
    .flatMap(p->Stream.of(
    String.format("название: %s цена без скидки: %d", p.getName(), p.getPrice()),
    String.format("название: %s цена со скидкой: %d", p.getName(), p.getPrice() -
    (int)(p.getPrice()*0.1))
    ))
    .forEach(s->System.out.println(s));
    9. Чем отличаются методы map() и flatMap().
    10. Расскажите про метод filter()
    Метод filter() является промежуточной операцией принимающей предикат, который фильтрует все элементы, возвращая только те, что соответствуют условию.
    Stream citiesStream = Stream.of("Париж", "Лондон", "Мадрид","Берлин", "Брюссель"); citiesStream.filter(s->s.length()==6).forEach(s->System.out.println(s));
    11. Расскажите про метод limit()
    limit(long n) применяется для выборки первых n элементов потоков. Этот метод также возвращает модифицированный поток, в котором не более n элементов.
    Stream phoneStream = Stream.of("iPhone 6 S", "Lumia 950", "Samsung Galaxy S 6", "LG G 4",
    "Nexus 7"); phoneStream.skip(1)
    .limit(2)
    .forEach(s->System.out.println(s)); //
    Lumia 950 Samsung Galaxy S 6
    12. Расскажите про метод skip()
    skip(long n) используется для пропуска n элементов. Этот метод возвращает новый поток, в котором пропущены первые n элементов.
    13. Расскажите про метод sorted()
    Для простой сортировки по возрастанию применяется метод sorted(). Подходит только для сортировки тех объектов, которые реализуют интерфейс Comparable.
    Если же у нас классы объектов не реализуют этот интерфейс или мы хотим создать какую-то свою логику сортировки, то мы можем использовать другую версию метода sorted(), которая в качестве параметра принимает компаратор. class Phone{ private String name; private String company; private int price; public Phone(String name,
    String comp, int price){ this.name=name; this.company=comp; this.price = price;
    } public String getName() { return name; } public int getPrice() { return price; } public String getCompany() { return company; }
    } import java.util.Comparator; import java.util.stream.Stream; public class Program { public static void main(String[] args) {
    Stream phoneStream = Stream.of(new Phone("iPhone
    X", "Apple", 600), new Phone("Pixel 2", "Google", 500), new Phone("iPhone 8", "Apple",450), new Phone("Nokia 9", "HMD Global",150), new Phone("Galaxy S9", "Samsung", 300)); phoneStream.sorted(new PhoneComparator())
    .forEach(p->System.out.printf("%s (%s) - %d \n", p.getName(), p.getCompany(), p.getPrice()));
    }
    }
    class PhoneComparator implements Comparator
    { public int compare(Phone a, Phone b){ return a.getName().toUpperCase().compareTo(b.getName().toUpperCase());
    }
    }
    14. Расскажите про метод distinct() “особый”
    возвращает только ункальные элементы в виде потока
    Stream people = Stream.of("Tom", "Bob", "Sam", "Tom", "Alice", "Kate", "Sam"); people.distinct().forEach(p -> System.out.println(p));
    15. Какие терминальные методы в стримах вы знаете?
    - forEach (принимает Consumer) например System.out::println (покажет все элементы, которые остались в стриме)
    - findFirst () первый в порядке следования элемент из стрима (возвращается OptionalInt, т.к. может вернуться 0)
    - allMatch (принимает предикат) позволяет удостовериться, удовлетворяют ли все элементы стрима определенному условию
    - min () возвращает минимальный элемент из стрима
    - count () возвращает количество элементов, оставшееся в стриме
    - sum () 0
    - collect () собирает элементы стрима в новое хранилище, например список. Куда может собрать – смотри список Collectors:
    - groupingBy группирует по параметрам
    - averagingInt среднеарифметическое какого то параметра
    - summarizingInt дает кол-во элементов, суммму, мин, ср.арифм, макс значения
    - reduce () – позволяет вычислить свертку элементов стрима (результат применения некоторого бинарного оператора к паре элементов из стрима, пока от стрима не останется один единсттвенный элемент) свёртка — это математическая операция, применённая к двум функциям f и g, порождающая третью функцию, которая иногда может рассматриваться как модифицированная версия одной из первоначальных
    16. Расскажите про метод collect() “собирать”
    собирает элементы стрима в новое хранилище, например список
    Эта функция представляет объект Collector, который определен в пакете java.util.stream. Java уже предоставляет ряд встроенных функций, определенных в классе Collectors:
    - toList(): преобразование к типу List
    - toSet(): преобразование к типу Set
    - toMap(): преобразование к типу Map
    - groupingBy() - разделяет коллекцию на несколько частей и возвращает Map>;
    - summingInt(), summingDouble(), summingLong() - возвращает сумму;
    List filteredPhones = phones.stream()
    .filter(s->s.length()<10)
    .collect(Collectors.toList());
    17. Расскажите про метод reduce() “уменьшить”
    Позволяет выполнять какое-то действие на всей коллекции и возвращать один результат вычислим произведение набора чисел:
    Stream numbersStream = Stream.of(1,2,3,4,5,6);

    Optional result = numbersStream.reduce((x,y)->x*y);
    System.out.println(result.get()); // 720
    18. Расскажите про класс Collectors и его методы.
    В Java 8 в классе Collectors реализовано несколько распространённых коллекторов:
    - toList(), toCollection(), toSet() - представляют стрим в виде списка, коллекции или множества;
    - toConcurrentMap(), toMap() - позволяют преобразовать стрим в Map;
    - averagingInt(), averagingDouble(), averagingLong() - возвращают среднее значение;
    - summingInt(), summingDouble(), summingLong() - возвращает сумму;
    - summarizingInt(), summarizingDouble(), summarizingLong() - возвращают SummaryStatistics с разными агрегатными значениями;
    - -partitioningBy() - разделяет коллекцию на две части по соответствию условию и возвращает их как
    Map;
    - groupingBy() - разделяет коллекцию на несколько частей и возвращает Map>;
    - mapping() - дополнительные преобразования значений для сложных Collector-ов.
    - Так же существует возможность создания собственного коллектора через Collector.of():
    Collector, List> toList = Collector.of(
    ArrayList::new,
    List::add,
    (l1, l2) -> { l1.addAll(l2); return l1; }
    );
    1   2   3   4   5


    написать администратору сайта