С каждой новой версией Java становится все богаче и богаче. Хотя зачастую основа богатств заложена в более ранних версиях, но язык продолжал совершенствоваться как в методологии, так и в реализации. Коллекции в Java не являются исключением.
Основной каркас коллекций появился в версии J2SE 1.2 и продолжал развиваться, претерпевая изменения, которые больше радовали, нежели огорчали. С выходом JDK 5 коллекции стали удобней, быстрее, а работать с ними стало легче. Это привело к тому, что программисты начали более интенсивней их эксплуатировать. Выработались некие паттерны по работе с ними, которые без всякого сомнения эффективны. Но с появлением JDK 8 коллекции снова стали лучше, а лучше они стали благодаря потокам.
Очевидно, благодаря тому, что коллекцию можно представить в виде потоков, будет меняться и методика работы с ними. Поэтому я хочу показать, как привычные и понятные решения c коллекциями становятся еще проще.
- Пример 1. Проще не бывает
- Пример 2. Найдем четные значения в списке и выведем их в консоль
- Пример 3. Посчитаем сколько слов в списке имеет длину 5 символов
- Пример 4. Вывести уникальные слова
- Пример 5. Длинные слова
- Пример 6. Слова с цифрами
- Пример 7. Выделяем числа
Пример 1. Проще не бывает
Конечно начнем с самого простого, пробежимся по всем элементам коллекции и выведем все элементы.
// создадим и заполним список
List<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 5, 6, 11, 3, 15, 7, 8);
// а теперь
// быстрый for по всем элементам, только для коллекций
for (Integer i:list){
System.out.println(i);
}
//но мы уже живем в JDK 8
//а значит нужно так
list.stream().forEach(System.out::println);
Как вы заметили, есть новый синтаксис, который, на мой взгляд, новичка в Java, гораздо проще.
Итак, что видно в новом синтаксисе:
берем_список(list).превращаем_в_поток(stream).перебираем_все_элементы(forEach)(тут_интуитивно_понятно)
System.out::println
— ссылка на статический метод, которая выводит строку на консоль
Вместо ссылки на статический метод можно использовать немного другую, пока менее понятную запись:
list.stream().forEach(i -> System.out.println(i));
в этой записи используется лямбда-выражения. И да, чтобы научится работать с потоками, нужно будет выучить лямбда-выражения – они прекрасны.
Далее я не буду показывать как работать с коллекциями используя только потоки, рассчитывая на то, что с традиционными способами вы познакомились в ходе курса.
Пример 2. Найдем четные значения в списке и выведем их в консоль
list.stream().filter(i -> i%2==0).forEach(System.out::println);
Вся задача решена в одну строчку. Надеюсь вам нравится работать в одну строчку. С помощью метода filter
мы профильтровали поток и то что осталось вывели на консоль.
Фильтр очень мощная штука, которая способна помочь в самых неожиданных случаях. Давайте поизвращаемся и изменим условия задачи. Например, нам нужно посчитать сколько четных чисел в списке:
long count = list.stream().filter(i -> i%2==0).count();
И снова в одну строчку. Как-то кажется все просто.
В фильтре мы использовали лямбда-выражение, тем самым поместив в новый поток только четные числа, а потом к новому потоку применили count
, который и посчитал сколько элементов в новом потоке.
Пример 3. Посчитаем сколько слов в списке имеет длину 5 символов
Поиграли с целыми числами, теперь поиграем со словами.
List<String> list = new ArrayList<>();
Collections.addAll(list, "разые", "слова", "интересные", "и", "не", "очень");
System.out.println(list.stream().filter(w -> w.length() == 5).count());
Мы снова воспользовались фильтром. В фильтре, с помощью лямбда-выражения вывели новый поток, а далее понятный count
посчитал, сколько в новом потоке элементов.
Пример 4. Вывести уникальные слова
Знакомая задача, когда мы прочитали в коллекцию из файла много разных слов, а теперь нам нужны только уникальные.
List<String> list = new ArrayList<>();
Collections.addAll(list, "Вася", "Таня", "Оля", "Вася", "Оля", "Сергей");
list.stream().distinct().forEach(System.out::println);
Основное действие было сделано над потоком с помощью distinct
.
Далее я предлагаю взглянуть на некоторые наши задачи из курса с помощью потоков
Пример 5. Длинные слова
На 9-м уровне Java Core, в 11 лекции есть интересная задача, в ней нужно записать через запятую в Файл2 слова, длина которых строго больше 6. Какой бы огород не городили, я предлагаю такой ход решения:Из файла источника читаем все слова в список.
Потом выполняем следующую строку
Optional<String> rezult = list.stream() .filter(w->w.length()>6) .reduce((w1,w2)->w1+", "+w2);
result.get()
записываем в файл.
Пример 6. Слова с цифрами
Записать через пробел в Файл2 все слова, которые содержат цифры, например, а1 или abc3d. Это тоже условие из нашего задачника, как вы догадались, решение простое.
Optional<String> rezult = list.stream()
.filter(w->w.matches(".*?\\d+.*?"))
.reduce((w1,w2)->w1+" "+w2);
Профильтровали поток с помощью регулярного выражения, а потом reduce и лямбда-выражение. Как много общего с предыдущей задачей.
Пример 7. Выделяем числа
Вся задача звучит так:- Считать с консоли 2 имени файла.
- Вывести во второй файл все числа, которые есть в первом файле.
- Числа выводить через пробел.
- Закрыть потоки.
Optional<String> rezult = list.stream().filter(w->w.matches("\\d+"))
.reduce((w1,w2)->w1+" "+w2);
System.out.println(rezult.get());
При помощи потоков задача решается очень простым способом. Но, о чудо, сравните это решение с двумя предыдущими самостоятельно.
Завершая статью, я хочу Вам признаться: ребята, я жульничал, когда подбирал примеры. Дело в том, что я выбрал наиболее простые примеры, с целью показать Вам на знакомых задачах незнакомую тему. Конечно же, потоки используются как для простых, так и для более сложных задач. Но как подчеркнул в своей книге Хорстман «Потоки данных действуют по принципу «что, а не как делать.», а значит многие, ранее сложные задачи, могут стать более простыми.
Не знаю как Вам, но мне потоки понравились, надеюсь, я не отбил у Вас охоту их поучить. И еще кое-что поясню:
- Я не ставил себе целью научить читателя использовать потоки в коллекциях, не настолько я опытный наставник. Я хотел показать Вам, что потоки это просто и очень интересно! Вообще это необходимость.
- Чем больше я понимаю потоки, тем больше я вижу задач, где они решают все проблемы из задачника курса, а значит, потоки придумали не напрасно.
- С потоками не только просто работать, но они еще имеют важное преимущество — при работе с большими массивами данных потоки чаще производительней.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ