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

ревью 6. Ревью 6. 5ч функциональное программирование


Скачать 106.74 Kb.
Название5ч функциональное программирование
Анкорревью 6
Дата25.02.2023
Размер106.74 Kb.
Формат файлаdocx
Имя файлаРевью 6.docx
ТипДокументы
#955098

1.Зачем нужно функциональное программирование, где оно применяется и в чем его отличие от программирования в стиле ООП или в процедурном стиле?



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

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

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

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

В ООП внимание уделяется объектам, их взаимодействию и идентичности.

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

- ФИ это интерфейс с одним единственным абстрактным методом;

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

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

Перечислить основные семейства ФИ? Что они принимают и что возвращают?

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

Consumer’ы – потребители, принимают какие-то данные, обрабатывают их в методе accept, но ничего не возвращают.

Supplier’ы – поставщики – ничего не принимают в качестве параметра, а просто возвращают какое-то значение

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

Function – функции – принимают аргумент и возвращают значение какого-то типа.

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

Декларативный и императивный методы описания

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

3.Обязательна ли аннотация @FunctionalInterface? НЕТ!

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

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

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

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

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

В реализации такого метода его дефолтный вариант вызывается тем же синтаксисом, что и внешний класс из вложенного: InterfaceName.super.methodName().
5.Может ли ФИ содержать что-то кроме абстрактного метода

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

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

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

Сколько дефолтных методов и статических методов, статических полей в интерфейсе? Не ограничено
Где находятся ФИ?в пакете java.util.function
6.Все способы реализации функционального интерфейса?

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

Какие есть способы инстанцировать ФИ

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

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

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

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

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

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

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

Consumer printer = System.out::println;

Function<Объект, String>objToString = Object::toString;
7. Что такое метод референс?

Ссылка на метод(метод референс)

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

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

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

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

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

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

ContainingType::methodName

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

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

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

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

8.Что такое “анонимные классы”:?

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

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

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

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

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

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

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

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

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

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

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

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

Любую ли лямбду можно заменить на анонимный класс

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

Где применяется АК

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

Рассмотрим создание 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. (Это объясняет, почему после закрывающей скобки стоит точка с запятой.)

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

Можно.

10. Что такое лямбла выражение? Как его записать?

Лямбда является реализацией абстрактного метода функционального интерфейса
Это сокращенная форма объявления внутреннего анонимного класса.

(parameter list) -> lambda body

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

Как взаимосвязаны лямбда и ФИ

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

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

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

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

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

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

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

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

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

да

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

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

11.Расскажите про Comparator и Comparable

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

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

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

Использование данных интерфейcов в своих приложениях позволяет упорядочивать (сортировать) данные.

Интерфейс Comparable

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

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

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

Интерфейс Comparator:

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

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

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

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

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

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

12. Что такое стримы? Для чего они нужны? Когда их лучше использовать?

-Способ работы со структурами данных в функциональном стиле.

-Упростить работу с наборами данных, в частности, упростить операции фильтрации, сортировки и другие манипуляции с данными

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

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

В каком пакете находится Stream java.util.stream.

Чем Stream отличается от итератора

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

По критерию обработки данных из стрима целевым устройством:

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

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

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

• конечные

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

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

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

• специальный тип (IntStream, DoubleStream)

14. Способы создания Стрима?

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


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

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

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

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

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

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

16.Что возвращают промежуточные операции над стримом?

Промежуточные (конвейерные) - возвращают трансформированный поток (стрим с какими-то изменениями).

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

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

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

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

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

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

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

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

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

map

17.В чем разница map и flatMap

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

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

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

19.Можно ли вызывать 2 теминальные операции?

Нет, только один раз. Терминальная операция завершает работу стрима.

20.Что будет, если терминальной операции не будет?

Все конвейерные методы выполняются лениво и пока не будет вызван терминальный метод никаких действий на самом деле не происходит.
21.Может ли стрим использоваться повторно?

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

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

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

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

В то же время если рабочая машина не является многоядерной, то поток будет выполняться как последовательный.
23.В чём разница между peek и forEach

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

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

В чем разница между foreach и foreachordered

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

какой функционал у каждого (forEach и peek)

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

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

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



***ДОП
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)


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