Главная страница

Подготовка к ревью 7 модуля core. Что такое функциональное программирование плюсы минусы, где применяется фп


Скачать 126.4 Kb.
НазваниеЧто такое функциональное программирование плюсы минусы, где применяется фп
АнкорПодготовка к ревью 7 модуля core
Дата09.03.2022
Размер126.4 Kb.
Формат файлаdocx
Имя файлаJC 7 new.docx
ТипДокументы
#388379

  1. Функциональные интерфейсы (ФИ), основные типы


Что такое функциональное программирование? плюсы минусы, где применяется

ФПпомогает сделать код более понятным, предсказуемым и легким для чтения. Использование принципов функционального программирования помогает избавиться от ненужных абстракций с непредсказуемым поведением, поэтому сделать программу более предсказуемой и уменьшить количество возможных ошибок.

ООП - подход подразумевает написание базовых классов и расширение существующих путем добавления к ним методов. Данные хранятся в экземпляре класса вместе с методами, которые ими оперируют. Функции в ООП зависят от внешних данных (например, содержат внутри себя ссылки на глобальные переменные) или коммуницируют с внешним миром (ввод-вывод)

В отличие от ООП, ФП характеризуется слабой связью функции с данными, которыми она оперирует. Это позволяет избежать побочных эффектов при выполнении функций — например чтения и изменения глобальных переменных, операций ввода-вывода и так далее. Детерминированные функции ФП возвращают один и тот же результат для одних и тех же аргументов.

Преимущества функционального программирования

  • Простое тестирование и отладка. Это возможно благодаря чистым функциям, которые используют неизменяемые значения, принимают аргументы и осуществляют выводы. С их помощью становится намного проще разрешать проблемы, возникающие в программе.

  • Ленивая оценка. Значение оценивается и сохраняется только в случае необходимости. Нет необходимости полной повторной оценки.

  • Применение и реализация параллелизма. Функциональное программирование полезно для реализации параллелизма. Это возможно благодаря чистым функциям, которые не вносят никаких изменений в данные и переменные.

  • Способность обрабатывать функции как значения. Значения передаются функциям в качестве параметров — от такой реализации код становится читаемым, простым и понятным.

  • Простота понимания чистых функций. Чистые функции зависят только от входных данных, они не меняют значения и состояния программы. Каким бы ни был результат, они возвращают изначальное значение.

  • Ориентирование на результаты, а не процесс. Важный момент в программировании — получение удобоваримого конечного результата.

  • Неизменяемые данные. Это значит, что можно легко создавать структуры данных и при этом не изменять уже существующие.

Недостатки функционального программирования

  • Объединение чистых функций с другими операциями ввода-вывода.

  • Неизменяемость и рекурсия иногда могут приводить к снижению производительности.

  • Рекурсия, в отличие от метода написание программ при помощи циклов, не слишком распространена, оттого может пугать и отталкивать.

  • Многие объекты создаются в момент кодирования, потому его сложно поддерживать.

  • Функциональное программирование позволяет избавиться от проблем и ошибок в коде, эффективно использует лямбда-исчисление, поддерживает вложенные функции. Оно предлагает большие возможности модульности при меньшем количестве строк кода, тем самым увеличивая продуктивность разработчика.

Применение функционального программирования

  • Часто ФЯ используют для создания искусственного интеллекта и высоконагруженных вычислительных систем.

  • Также ФЯ применяются в DataScience и BigData. Эта область требует выполнения огромного количества вычислений за короткий промежуток времени, без нагрузки на аппаратную часть оборудования. Вот здесь чаще всего и используют функциональные языки, а императивные для создания интерфейса.



Что такое ФИ

Интерфейс называется функциональным, если в нем имеется ровно один абстрактный метод.
Перечислить основные семейства ФИ? Что они принимают и что возвращают?

Основные семейства из стандартной библиотеки:

• Consumer’ы – потребители, принимают какие-то данные, обрабатывают их в методе accept, но ничего не возвращают. (IntConsumer, LongConsumer, DoublConsumer для обработки примитивных типов и BiConsumer для двух параметров)

• Supplier’ы – поставщики – ничего не принимают в качестве параметра, а просто возвращают какое-то значение (BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier)

• Predicate’ы – принимают значение какого-то типа, возвращает boolean значение (true/false). (IntPredicate, LongPredicate, DoublePredicate, BiPredicate)

• Function – функции – принимают аргумент и возвращают значение какого-то типа. (BiFunction, DoubleFunction-принимает дабл возвращает объект… и др.)

• Операторы – (UnaryOperator, BiOperator) – частный случай функций – принимают и возвращают значения одного и того же типа.
Декларативный и императивный методы описания

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

Императивный подход:

● в исходном коде программы записываются инструкции (команды);

● инструкции должны выполняться последовательно;

● данные, получаемые при выполнении предыдущих инструкций, могут читаться из памяти последующими инструкциями;

● данные, полученные при выполнении инструкции, могут записываться в память.

*Если кратко, то императивная программа содержит прямые указания, что должен сделать компьютер и в каком порядке должны выполняться инструкции. Примерами императивных языков являются Java, Python, JavaScript, C, C++.Декларативная же программа состоит из ограничений и правил, из которых компьютер генерирует способ получения результата. Пример декларативного языка: SQL.
Для чего нужен ФИ и зачем был добавлен

Благодаря Ф.И. стало возможно избавиться от монструозного синтаксиса с анонимными классами и использовать компактные лямбда выражения и ссылки на методы, это открыло возможность писать на Java программы в функциональном стиле, характерном для функциональных языков программирования, это когда программа записывается как последовательное применение функций к некоторым значениям и другим функциям, а не как сложная структура из циклов, условных операторов и перекладывания значений переменных туда-сюда.
(- ФИ это интерфейс с одним единственным абстрактным методом;

- Функциональные интерфейсы посредством их реализации через лямбда выражения позволяют писать код в функциональном стиле.)
Какой аннотацией помечается ФИ

Аннотация @FunctionalInterface не является чем-то сверхсложным и важным, так как её предназначение - сообщить компилятору, что данный интерфейс функциональный и должен содержать не более одного метода. Если же в интерфейсе с данной аннотацией более одного нереализованного (абстрактного) метода, компилятор не пропустит данный интерфейс, так как будет воспринимать его как ошибочный код. Интерфейсы и без данной аннотации могут считаться функциональными и будут работать, а @FunctionalInterface является не более чем дополнительной страховкой.
Обязательна ли аннотация @FunctionalInterface нет. см выше
Может ли ФИ содержать что-то кроме абстрактного метода

Может содержать дефолтные методы, приватные и статические методы, статические поля – константы.

Эти методы реализуют какую-то дополнительную логику (например объединение предикатов конъюнкция (p1.and(p2)) или получение обратного предиката p1.nigate();)

Они необходимы для обратной совместимости, чтобы добавить функционал интерфейса, при этом не меняя сам класс.Применяяметоды с реализациейесть возможность не ломать старый код, которыйнаписан ранее.
Что такое default методы в интерфейсе и для чего они были введены

(для обратной совместимости)

В Java 8 вместе с лямбдами и стримами появилась острая необходимость дополнить стандартные интерфейсы новыми методами. Никто не собирался ломать обратную совместимость, и было предложено добавить методы по умолчанию.

Теперь добавление ключевого слова default к методу интерфейса позволяет добавить ему тело. Все новые методы старых интерфейсов снабжаются дефолтной реализацией.

В реализации такого метода его дефолтный вариант вызывается тем же синтаксисом, что и внешний класс из вложенного: InterfaceName.super.methodName().
Сколько дефолтных методов и статических методов, статических полей в интерфейсе?Не ограничено
Где находятся ФИ?в пакете java.util.function
Какие есть способы инстанцировать ФИ

* через экземпляр класса, реализующий функциональный интерфейс.

* через лямбда-выражение (если логика метода состоит из нескольких инструкций и требуется оператор return – то они заключаются в фигурные скобки, а если вся логика это только одно выражение, то скобки можно опустить.)

* через ссылку на обычный нестатический метод (через конкретный объект (ссылку на негго) и имя метода, или через имя класса и имя метода но передав сам объект в качестве параметра.)

* через ссылку на статический метод (через имя класса и имя метод)

* через конструктор (через имя класса и оператор new)

* через анонимный класс (объявить его через переменную типа функционального интерфейса)
Все способы реализации ФИ (4 штуки: ссылка на метод, лямбда, через анонимный класс, через обычную имплементацию в классе.)
Как можно инстанцировать через ссылку на нестатический метод

Через ссылку на экземпляр класса и имя метода, или через имя класса и имя метода, но передав при этом в качестве параметра на первом месте сам объект

Consumer printer = System.out::println;

Function<Объект, String>objToString = Object::toString;
Расскажитепро Comparator и Comparable

Интерфейс Comparable содержит один единственный метод int compareTo(E item), который сравнивает текущий объект с объектом, переданным в качестве параметра. То есть для сравнения объектов необходимо чтобы класс реализовывал данный интерфейс.

Но если данный интерфейс не реализован или логика сравнения в его реализации требует изменений, то можно прибегнуть к функциональному интерфейсу Comparator для которого требуется реализовать абстрактный метод int compare(T o1, T o2), при вызове которого и передачи в него сравниваемых объектов в качестве параметров будет происходить их сравнение по определяемой нами логики. (отрицательный результат – второй объект больше, положительный – первый объект больше, 0 – объекты равны.)

*Через компаратор можно создавать сколько угодно различных реализаций сравнения.
В чем разница между Comparable и Comparator

Два новых интерфейса java.lang.Comparable и java.util.Comparator были добавлены в версии Java 5. Использование данных интерфейcов в своих приложениях позволяет упорядочивать (сортировать) данные.

Интерфейс Comparable

В интерфейсе Comparable объявлен только один метод compareTo (Objectobj), предназначенный для упорядочивания объектов класса. Данный метод удобно использовать для сортировки списков или массивов объектов.

Метод compareTo (Objectobj) сравнивает вызываемый объект с obj. В отличие от метода equals, который возвращает true или false, compareTo возвращает:

0, если значения равны;

Отрицательное значение (обычно -1), если вызываемый объект меньше obj;

Положительное значение (обычно +1), если вызываемый объект больше obj.

Если типы объектов не совместимы при сравнении, то compareTo (Objectobj) может вызвать исключение ClassCastException. Необходимо помнить, что аргумент метода compareTo имеет тип сравниваемого объекта класса.

Обычныеклассы Byte, Short, Integer, Long, Double, Float, Character, String ужереализуютинтерфейс Comparable.

Интерфейс Comparator:

ВинтерфейсеComparatorобъявленметодcompare (Objectobj1, Objectobj2), которыйпозволяетсравниватьмеждусобойдваобъекта. На выходе метод возвращает значение 0, если объекты равны, положительное значение или отрицательное значение, если объекты не тождественны.

Отличие интерфейсов Comparator и Comparable

Интерфейс Comparable используется только для сравнения объектов класса, в котором данный интерфейс реализован. Т.е. interfaceComparable определяет логику сравнения объекта определенного ссылочного типа внутри своей реализации (по правилам разработчика).

Comparator представляет отдельную реализацию и ее можно использовать многократно и с различными классами. Т.е. interfaceComparator позволяет создавать объекты, которые будут управлять процессом сравнения (например при сортировках).
Как взаимосвязаны лямбда и ФИ

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

приводит к некоторой форме анонимного класса.

Кроме того, в функциональном интерфейсе определяется целевой тип - тип контекста, в котором это лямбда-выражение встречается, – например, тип локальной переменной, которой оно присваивается, или тип параметра метода, вместо которого оно передается. Лямбда-выражение можно использовать только в том контексте, в котором определен его целевой тип.
Отличие BinaryOperator от Function

BinaryOperator принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T:

Функциональный интерфейс Function представляет функцию перехода от объекта типа T к объекту типа R:



  1. Что такое лямбда выражение (ЛВ) и ссылка на метод


Что такое ЛВ

Это сокращенная форма объявления внутреннего анонимного класса, так называемый синтаксический сахар. Компилятор знает ожидаемый интерфейс, имя метода и типы параметров для этого интерфейса, поэтому это можно опустить – он это подставит сам, а указать для лямбда имя параметров и тело метода-инструкции над этими параметрами и для ссылки на метод – просто указать сам этот метод и имя класса или объект.

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

Лямбда выражение сокращенная форма записи анонимного класса. Ссылка на метод сокращенная форма записи лямбда выражения.

Оператор “::” - ссылка на метод, который реализован.

Если лямбда выражения вызывают только один существующий метод, лучше ссылаться на этот метод по его имени. Ссылки на методы (MethodReferences) – это компактные лямбда выражения для методов, у которых уже есть имя.

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

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

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

ContainingType::methodName

4. Ссылканаконструктор: ClassName::new
В каком виде передается ссылка на метод?

- имя класса::имя стат метода (для статического метода);

- объект класса::имя метода (для метода экземпляра);

- название класса::new (для конструктора)
Как ЛВ связан с анонимным классом

Лямбда  - выражение  — это краткая форма для написания анонимного класса . Используя лямбда-выражение, мы можем объявлять методы без имени.
ЛВ являются сокращенной записью, объявления анонимного класса. Компилятор сам создаст версию класса и переопределит нужный метод.

К каким переменным есть доступ из ЛВ

Лямбда-выражение может использовать переменные, которые объявлены во вне, в более общей области видимости - на уровне класса или метода, в том числе статическим, в котором лямбда-выражение определено. Однако в зависимости от того, как и где определены переменные, могут различаться способы их использования в лямбдах.

Переменные, объявленные на уровне класса, мы можем получить и даже изменить в лямбда-выражении.
public class LambdaApp {
static int x = 10;

static int y = 20;
public static void main(String[] args) {
Operation op = () -> {
x = 30;

return x + y;

};

System.out.println(op.calculate()); // 50

System.out.println(x); // 30 - значение x изменилось

}

}
interface Operation {

int calculate();

}
Локальные переменные уровня метода мы также можем использовать в лямбдах, но изменять их значение нельзя, они должны быть эффективно финальными или объявленными final.

public static void main(String[] args) {
int n = 70;

int m = 30;

Operation op = () -> {
//n=100; - так нельзя сделать

return m + n;

};

// n=100; - так тоже нельзя

System.out.println(op.calculate()); // 100

}

К каким переменным и как можно обращаться в теле ЛВ

переменные внутри метода (эффективно-финальные), static переменные класса, переменные интерфейса (с которым лямбда работает)) (также смотреть предыдущий вопрос)
Можно ли использовать лямбду без параметров

Да, если реализуемый метод не принимает параметров.

Может ли быть тело метода в несколько строчек в лямбда-выражении

да
Чем отличается однострочная запись лямбда-выражения от многострочной

Простотой чтения.В многострочной реализации необходимо указывать фигурные скобки и нужно написать в конце return.


  1. Как ЛВ связаны с анонимным классом


Анонимные классы АК

- это вид вложенных внутренних классов, отличительной особенностью которых является что создание объекта и описание его класса происходит при инициализации переменной, ссылающейся на этот объект. Эта переменная может иметь тип родительского класса, тогда анонимный класс наследуется от родительского класса, а может иметь тип какого-либо интерфейса, тогда анонимный класс реализует данный интерфейс. Применяется когда такую реализацию нужно использовать единожды.

АК — это вложенные без имени класса. Они обычно объявляются либо как подклассы существующего класса, либо как реализации некоторого интерфейса. Определяются, когда они создаются. Применяется при создании объекта, когда нужно расширить класс или реализовать интерфейс.

Анонимные классы могут быть созданы:

1. Как реализация интерфейса;

2. Как наследник определенного класса;

3. Если анонимный класс объявлен в статическом блоке:

● его второй экземпляр можно создать путем вызова метода getClass().newInstance() из объекта класса и переиспользовать ту же логику, но уже в другом инстансе: otherInstance.accept().

4. Если анонимный класс был объявлен внутри нестатического блока:

● нужно передать в его конструктор ссылку на обрамляющий класс. В противном случае получим InstantiationException.
Любой анонимный класс можно заменить на лямбду?

На вопрос любой ли анонимный класс можно заменить на лямбду, нужно отвечать - с одним абстрактным методом. А функциональное программирование, кроме стрима применяется в лямбде.

Нет - только тот анонимный класс, который будет имплементировать функциональный Interface

Нет, т.к. лямбда-выражение может реализовывать только один метод. Поэтому на лямбда-выражением можно заменить анонимный класс, который реализует один абстрактный метод функционального интерфейса.
Любую ли лямбду можно заменить на анонимный класс

Да, так как лямбда в Java — упрощённая запись анонимного класса, реализующего функциональный интерфейс
Где применяется АК

Анонимные классы позволяют сделать ваш код более кратким. Они позволяют вам объявить и создать экземпляр класса одновременно, применяются для реализации интерфейсов, если нужно применить такой объект единожды и забыть про него. Используйте их, если вам нужно использовать локальный класс только один раз.

Как создать АК, особенно как создать экземпляр.

Анонимный класс — это выражение. Синтаксис выражения анонимного класса аналогичен вызову конструктора, за исключением того, что определение класса содержится в блоке кода.
Рассмотрим создание frenchGreeting объекта:
HelloWorld frenchGreeting = new HelloWorld() {

String name = "tout le monde";

public void greet() {

greetSomeone("tout le monde");

}

public void greetSomeone(String someone) {

name = someone;

System.out.println("Salut " + name);

}

};

Выражение анонимного класса состоит из следующего:

  • Оператор new

  • Имя интерфейса для реализации или класса для наследования. В этом примере анонимный класс реализует интерфейс HelloWorld.

  • Круглые скобки, содержащие аргументы конструктора, как обычное выражение создания экземпляра класса. Примечание: При реализации интерфейса конструктор отсутствует, поэтому вы используете пустую пару круглых скобок, как в этом примере.

  • Тело, которое является телом объявления класса. В частности, в теле разрешены объявления методов, но не операторы.

Поскольку определение анонимного класса является выражением, оно должно быть частью оператора. В этом примере выражение анонимного класса является частью оператора, которая создает экземпляр объекта frenchGreeting. (Это объясняет, почему после закрывающей скобки стоит точка с запятой.)

Что такое анонимный класс и чем он отличается от обычного класса?

Анонимный класс - одноразовый класс, который создается автоматически при реализации функционального интерфейса или расширения существующего класса, после чего удаляется сборщиком мусора. Не имеет имени.

От обычного отличается тем, что не нужно прописывать создание объекта класса (создается автоматически), не занимает места, т.к. используется единожды, а затем удаляется.
Можно ли в одном анонимном классе реализовать или переопределить два метода

Можно.
4) Что такое Стрим
Что такое стримы

Способ работы со структурами данных в функциональном стиле.
Для чего нужныСтримы
Когда их лучше использовать
Чем является Stream в контексте Java

- Stream API — это способ работать со структурами данных в функциональном стиле.
В каком пакете находится Stream java.util.stream.
Чем Stream отличается от итератора

1. Порядок в обходе от итератора может быть задан и заранее определен.

2. Стоимость (затраты мощностей процессора) доступа к элементам в стримах гораздо ниже.

3. Протокол Iterator принципиально менее эффективен.

Для получения каждого элемента требуется вызов двух методов. Кроме того, поскольку итераторы должны быть устойчивы к таким вещам, как вызов next() без hasNext() или hasNext() несколько раз без next(), оба этих метода обычно должны выполнять некоторую защитную кодировку ( и, как правило, больше состояния и ветвления), что увеличивает неэффективность.
Чем Stream отличается от коллекции

Разница между коллекцией (Collection) данных и потоком (Stream) из новой JDK8 в том, что коллекции позволяют работать с элементами по-отдельности, тогда как поток(Stream) не позволяет. Например, с использованием коллекций, вы можете добавлять элементы, удалять, и вставлять в середину.

Стрим может быть многопоточным;

В стриме ниже потребляемость ресурсов на совершение операций;

Коллекции позволяют работать с элементами по отдельности;

Если в коллекции меняются значения, то это влияет на исходную коллекцию;

Если на основе коллекции создается стрим и меняются значения, то исходная коллекция не меняется.

**Коллекции предполагают хранение набора элементов, и соответственно, конечны, а стрим потенциально может быть бесконечным. Коллекции часто предоставляют индивидуальный доступ к своим элементам (по индексу или по ключу), а стрим такого не позволяет. Коллекции можно менять – добавлять или удалять элементы, в том числе через итератор, а применение трансформаций к стриму никак не влияет на тот источник, из которого элементы берутся (Владыкин).
Из каких частей состоит использование стримов

1 - порождение стрима, то откуда можно получить стрим

2 - промежуточные операции, изменяющие состояние стрима

3- терминальные операции, производящие результат. Эти операции запускают стрим на исполнение.
В каком случае нужно закрывать стрим

Только потоки, источником которых является канал ввода-вывода, например Files.lines(Path, Charset) должны быть закрыты. Остальные реализуют AutoCloseable.

*если стрим выделял какие-то системные ресурсы (работа с файлами или директориями), чтобы избежать утечек ресурса

Что такое ленивая инициализация стрима

Создание стрима происходит в момент выполнения терминальной операции.

Ленивая инициализация - это концепция отсрочки создания объекта до тех пор, пока объект не будет фактически впервые использован. При правильном использовании это может привести к значительному повышению производительности. Все промежуточные операции выполняются только тогда, когда есть терминальная операция. Терминальные (“terminal”, еще называют “eager”) - обрабатывают элементы и завершают работу стрима, так что терминальный оператор в цепочке может быть только один.

Для чего нужны параллельные стримы

Распараллеливание потоков позволяет задействовать несколько ядер процессора (если целевая машина многоядерная) и тем самым может повысить производительность и ускорить вычисления. Фактически применение параллельных потоков сводится к тому, что данные в потоке будут разделены на части, каждая часть обрабатывается на отдельном ядре процессора, и в конце эти части соединяются, и над ними выполняются финальные операции.

Чтобы сделать обычный последовательный поток параллельным, надо вызвать у объекта Stream метод parallel. Кроме того, можно также использовать метод parallelStream() интерфейса Collection для создания параллельного потока из коллекции.

В то же время если рабочая машина не является многоядерной, то поток будет выполняться как последовательный.
Первый этап работы со стримом

порождение стрима, то откуда можно получить стрим

  1. Из любой коллекции при помощи метода stream().

  2. Из BufferedReader методом lines(), который вернет поток строчек, строк из данного потока символов

  3. Создание стрима из файла (каждая строка в файле будет отдельным элементом в стриме): Files.lines(путь_к_файлу)

  4. Из директории на диске при помощи методов Files.list(path – вернет содержимое директории на один уровень) и Files.walk(path – рекурсивно обойдет и поддиректории)

  5. 2 и 3 пункт нужно закрывать и удобно использовать в try-with-resources

  6. Создание стрима из строки: «строка».chars()

  7. Создать динамически – при помощи некоторого саплаера(поставщика): Stream.generate(Math::random)

  8. Создание бесконечных стрима: Stream.iterate(начальное_значение, итерация) или Stream.generate(выражение_генерации) – для константных или случайных значений

  9. Получить диапазон чисел IntStream.range(0, 100) и IntStream.rangeClosed(0, 100) в виде стрима

  10. Конкатенацией двух других стримов IntStream.concat(stream1, stream2)

  11. Взять пустой стрим IntStream.empty()

  12. Получить стрим из массива: lines(путь_к_файлу)Arrays.stream(массив)

  13. Создание стрима из значений: Stream.of(значение1,…значениеN) явно

  14. СпомощьюStream.builder: Stream.builder().add(...)....build()

  15. Создание параллельного стрима: collection.parallelStream()


Как получить стрим диапазона чисел

IntStream.rangeClosed, IntStream.range
Можно ли конкатенировать стримы? если да, то каким методом

Их можно объединить с помощью метода Stream.concat:

Stream.concat(s1, s2).forEach(System.out::println);

Stream.concat объединит элементы из двух стримов в один стрим. ОбъединениестримовIntStream, LongStream, DoubleStream.
Можно ли получить пустой стрим? если да, то каким методом

Stream empty() возвращает пустой последовательный поток.

Пустой поток может быть полезен, чтобы избежать исключений нулевого указателя при вызове методов с параметрами потока.
Какполучитьстримизмассива

Double[] array = ..;

DoubleStream s = Arrays.stream(array);

…Stream.of(array);
Разница методов list() и walk()

Files.list() возвращает массив файлов в указанной директории

Files.walk() возвращает поток файлов в указанной директории и субдиректориях.
Что такое саплаер-поставщик? какой содержит метод

Стандартный функциональный интерфейс из пакета java.util.function, они не принимают ничего в качестве параметра, а просто возвращают какое-то значение. Помимо параметризованного саплаера, есть Boolean, Int, Long и Double саплаеры. Имеют единственный метод get()


Как динамически получать стрим

Создать динамически – при помощи некоторого саплаера(поставщика): Stream.generate(Math::random)
В чем разница методов range и rangeClosed

Различие функции range от rangeClosed в том, что в функции range правая граница не включается, а в функции rangeClosed включается.
Второй этап работы со стримом- промежуточные операции. См ниже
Что такое коллекторы

Класс Collectors из пакета java.util.stream служит для вывода элементов стрима в коллекцию.
В чем разница map и flatMap

.map используется когда нужно поработать с элементами коллекции, а .flatmap когда нужно поработать с элементами элементов коллекции (например лист листов).
В чем разница между foreach и foreachordered

Это терминальные методы служат для выполнения какого-либо действия над элементом стрима. forEachOdered используется обычно в параллельных стримах когда нужно соблюсти порядок выполнения действий над элементами.
В чём разница между peek и forEach

первый промежуточный, второй - терминальный

- peek выполняет какую-то функцию (принимает Consumer) над каждым элементом стрима и возвращает тот же стрим. Служит для отладки, чтобы можно было посмотреть как проходит метод chainingpeek(System.out::println)
какой функционал у каждого (forEach и peek)

peek() - возвращает тот же самый объект, который получил на входе, c применением к нему какой-то функции, возможно, с изменённым внутренним состоянием.

forEach - Применяет функцию (Consumer) к каждому элементу стрима, порядок при параллельном выполнении не гарантируется.

Может ли стрим использоваться повторно?

Если к тем же элементам необходимо применить еще какое-либо преобразование (посчитать по ним другое значение), то нужно заново сконструировать стрим, снова настроить и запустить какой-то терминальной операцией (Владыкин)

***Не обязательно заново собирать стрим! Можно в необходимом состоянии сохранить его в коллекцию, а потом уже создавать новые стримы из этой коллекции неограниченное количество раз
Третий этап работы со стримом

- терминальные операции, производящие результат. Эти операции запускают стрим на исполнение. См. ниже
5) Какие бывают стримы (По разным критериям, например "конечные и бесконечные")
Какие бывают стримы

знать 3 группы: 1) конечные и бесконечные, 2) последовательные и параллельные 3) объектные и примитивные спрашивает про параллельные, промежуточные и терминальные (конечные и бесконечные это)
По критерию обработки данных из стрима целевым устройством:

• параллельные (распараллеливание потоков по ядрам процессора для ускорения вычислений)

• последовательные (линейный - возвращает другой стрим)

По критерию ограниченности количества элементов в стриме:

• конечные

• бесконечные

По критерию типа содержащихся в стриме элементов:

• обобщенный тип (дженерик)

• специальный тип (IntStream, DoubleStream)
6) Терминальные и промежуточные методы.
Терминальные и промежуточные операции + примеры
Промежуточные (конвейерные) - возвращают трансформированный поток (стрим с какими-то изменениями).

• filter - Отфильтровывает элементы, возвращает только элементы, соответствующие условию ((n->n> 100) - принимает предикат - 100)

• skip- Позволяет пропустить N первых элементов

• distinct- Возвращает стрим без дубликатов (для метода equals)

• map- Преобразует каждый элемент стрима ((Integer::toString)принимает функцию, которая из каждого элемента стрима делает какой-то новый элемент потенциально другого типа)

• peek- Возвращает тот же стрим, но применяет функцию к каждому элементу стрима

• limit- Позволяет ограничить выборку определенным количеством первых элементов

• sorted- Позволяет сортировать значения либо в натуральном порядке, либо задавая для объектов Comparator

• flatMap- Похоже на map, но может создавать из одного элемента несколько

• flatMapToInt- Похоже на map, но принимает функцию, возвращающую стрим (s ->s.chars() –принимает функцию, которая для каждой строки возвращает стрим ее символов)
Терминальные (конечные) - возвращают конкретный результат (объект, примитив, коллекция и тд).

• findFirst- Возвращает первый элемент из стрима (возвращает Optional, тк стрим может быть пустой, и в нем нет элементов)

• findAny- Возвращает любой подходящий элемент из стрима (возвращает Optional)

• collect- Представление результатов в виде коллекций и других структур данных, например список collect.(Collectors.toList())

• count- Возвращает количество элементов, оставшихся в стриме

• anyMatch- Возвращает true, если условие выполняется хотя бы для одного элемента

• noneMatch- Возвращает true, если условие не выполняется ни для одного элемента

• allMatch- Возвращает true, если условие выполняется для всех элементов (stream.allMatch(n->n.length()> 100) - позволяет проверить, что все элементы стрима удовлетворяют условие предиката)

• min- Возвращает минимальный элемент, в качестве условия использует компаратор(возвращает Optional)

• max- Возвращает максимальный элемент, в качестве условия использует компаратор

• forEach- Применяет функцию к каждому объекту стрима, порядок при параллельном выполнении не гарантируется (stream.foreach(System.out::println) –принимает конзьюмера, которому будут отданы все элементы, которые в стриме остались)

• forEachOrdered- Применяет функцию к каждому объекту стрима, сохранение порядка элементов гарантирует

• toArray- Возвращает массив значений стрима

• reduce- Позволяет выполнять агрегатные функции на всей коллекцией и возвращать один результат (свертка элементов стрима, т.е результат применения некоторого бинарного оператора к каждой паре элементов стрима, пока от стрима не останется 1 элемент, который и есть результат свертки)

• sum– вернет арифметическую сумму элементов;
*у stream'a может быть сколько угодно вызовов конвейерных вызовов и в конце один терминальный, при этом все конвейерные методы выполняются лениво и пока не будет вызван терминальный метод никаких действий на самом деле не происходит.
Сколько раз можно вызывать терминальную операцию?

Только один раз
Что возвращают промежуточные операции над стримом?

Промежуточные (“intermediate”, ещё называют “lazy”) - обрабатывают поступающие элементы и возвращают стрим. Промежуточных операторов в цепочке обработки элементов может быть много.

Промежуточные операции возвращают трансформированный поток. Например, метод принимает поток чисел и возвращает уже преобразованный поток, в котором только числа больше 0.Промежуточная/ленивая - не будет исполняться до того момента, пока не будет вызвана терминальная операция.
Что возвращают терминальные операции над стримом?

**Терминальная - это метод, который возвращает void или возвращает другой тип с стрима.

Могут возвращать один или несколько элементов стрима (объект или примитив) (findFirst, findAny, count, min, max)
Коллекцию (collect)
Булевое значение (anyMatch, noneMatch, allMatch)
Массив элементов (toArray)
Сумму элементов (sum)

7) Способы получения стрима.

• Создание стрима из коллекции: collection.stream()

• Создание стрима из массива: Arrays.stream(массив)

• Создание стрима из значений: Stream.of(значение1,…значениеN)

• Создание стрима из файла (каждая строка в файле будет отдельным элементом в стриме): Files.lines(путь_к_файлу)

• Создание стрима из строки: «строка».chars()

• СпомощьюStream.builder: Stream.builder().add(...)....build()

• Создание параллельного стрима: collection.parallelStream()

• Создание бесконечных стрима :Stream.iterate(начальное_значение, итерация) или Stream.generate(выражение_генерации) – для константных или случайных значений.
***ДОП
Optional (зачем нужен)

Optional- это контейнер объекта, он может содержать значение или некоторый тип Т, или просто быть null. Он предоставляет много полезных методов избавляющие от добавления повторяющихся if null/notNull проверок, что позволяет нам сфокусироваться на том, что мы хотим сделать.МетодisPresent() возвращает true если экземпляр Optional содержит не null значение и false в противном случае. Метод orElseGet() содержит запасной механизм результата, если Optional содержит null, принимая функции для генерации значения по умолчанию. Метод map() преобразует текущее значение Optional и возвращает новый экземпляр Optional. Метод orElse() похож на orElseGet(), но вместо функции он принимает значение по умолчанию.
Objects (зачем нужен)

Этот класс состоит из статических служебных методов для работы с объектами. Эти утилиты включают нулевые или нулевые методы для вычисления хэш-кода объекта, возврата строки для объекта и сравнения двух объектов.
Java7 представила класс java.util.Objects, Objects предоставляет множество методов класса инструментов, включая метод isNull (Java8 представил метод isNull), в чем разница между java.util.Objects.isNull и object == null? Почему был введен метод java.util.Objects.isNull?Так как это то же самое, зачем вам метод isNull?
Причина метода isNull заключается в том, что ‘тот метод существует для использования в качестве предиката стрима filter(Objects::isNull)}
Лямбда была введена в Java8, поэтому существует много таких записей, как filter (Objects :: isNull), который, очевидно, более интуитивен, чем filter(x-> x == null).
Аналогично с методом boolean nonNull(Object obj) - filter(Objects::nonNull)
Задача 7.1.9 что возвращает метод?

Экземпляр Function из лямбда-выражения, в котором есть условный оператор (при выполнении условия, выполняется один из двух сценариев). У лямбда-выражения есть параметр, а у функциональных интерфейсов Predicate (вызывается condition над этим параметром)  и Function(вызываются ifTrue и ifFalse) методы.


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