1. Нововведения в Java 8: Функциональное программирование
Вместе с выходом Java 8 в ней появилась мощная поддержка функционального программирования. Можно даже сказать, долгожданная поддержка функционального программирования. Код стал писаться быстрее, хотя читать его стало сложнее 🙂
Перед изучением функционального программирования в Java, рекомендуем хорошо разобраться в трех вещах:
- ООП, наследование и интерфейсы (1-2 уровни квеста Java Core).
- Дефолтная реализация методов в интерфейсе.
- Внутренние и анонимные классы.
Хорошая новость заключается в том, что без знания всего этого можно пользоваться многими возможностями функционального программирования в Java. Плохая новость — понять, как именно все устроено и как все работает, без тех же внутренних анонимных классов уже сложно.
В ближайших лекциях мы сосредоточимся на том, как легко и просто пользоваться возможностями функционального программирования в Java, без глубокого понимания, как оно устроено.
Чтобы разобраться во всех нюансах функционального программирования в Java, нужны месяцы. Читать же такой код можно научиться за несколько часов. Поэтому предлагаем начать с малого. Да хоть с тех же потоков ввода-вывода.
2. Потоки ввода-вывода: цепочки потоков
Помните, когда-то вы изучали потоки ввода-вывода: InputStream
, OutputStream
, Reader
, Writer
и т.п.?
Были классы-потоки, которые читали данные из источников данных, такие как FileInputSteam
, а были и промежуточные потоки данных, которые читали данные из других потоков, такие как InputStreamReader
и BufferedReader
.
Эти потоки можно было организовывать в цепочки обработки данных. Например, так:
FileInputStream input = new FileInputStream("c:\\readme.txt");
InputStreamReader reader = new InputStreamReader(input);
BufferedReader buff = new BufferedReader(reader);
String text = buff.readLine();
Важно отметить, что в первых нескольких строках кода мы просто конструируем цепочку из Stream
-объектов, но реальные данные по этой цепочке потоков еще не передаются.
И только когда мы вызовем метод buff.readLine()
, произойдет следующее:
- Объект
BufferedReader
вызовет методread()
у объектаInputStreamReader
- Объект
InputStreamReader
вызовет методread()
у объектаFileInputStream
- Объект
FileInputStream
начнет читать данные из файла
Т.е. никакого движения данных по цепочке потоков нет, пока мы не начали вызывать методы типа read()
или readLine()
. Само конструирование цепочки потоков данные по ним не гоняет. Потоки сами данные не хранят, а только читают из других.
Коллекции и потоки
Начиная с Java 8, появилась возможность получить поток для чтения данных у коллекций (и не только у них). Но и это еще не самое интересное. На самом деле появилась возможность легко и просто конструировать сложные цепочки потоков данных, при этом тот код, который раньше требовал 5-10 строк, теперь можно было записать в 1-2 строки.
Пример — находим строку максимальной длины в списке строк:
Поиск строки максимальной длины |
---|
|
|
3. Интерфейс Stream
Расширенная поддержка потоков в Java 8 реализована с помощью интерфейса Stream<T>
. Где T
— это тип-параметр, обозначающий тип данных, которые передаются в потоке. Другими словами, поток полностью независим от типа данных, которые он передает.
Чтобы получить объект-поток у коллекции, достаточно вызвать у нее метод stream()
. Выглядит этот код примерно так:
Stream<Тип> имя = коллекция.stream();
При этом коллекция будет считаться источником данных потока, а объект типа Stream<Тип>
– инструментом по получению данных из коллекции именно в виде потока данных.
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Привет", "как", "дела?");
Stream<String> stream = list.stream();
Кстати, можно получить поток не только у коллекции, но и у массива. Для этого нужно воспользоваться методом Arrays.stream();
Пример:
Stream<Тип> имя = Arrays.stream(массив);
При этом массив будет считаться источником данных для потока имя
.
Integer[] array = {1, 2, 3};
Stream<Integer> stream = Arrays.stream(array);
После создания объекта Stream<Тип>
никакого движения данных не происходит. Мы просто получили объект-поток для того, чтобы начать строить цепочку из потоков-данных.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ