7 июня 2016 г.

Stream API в Java 8

Актуальная версия статьи доступна на моём сайте devmark.ru

В Java 8 появилось довольно важное нововведение под названием Stream. И здесь имеются в виду не потоки ввода/вывода. Stream - это абстракция, позволяющая с любыми объектами работать как с потоками. Порой это чем-то похоже на выполнение запросов к БД. Рассмотрим несколько типовых задач, с которыми часто сталкивается каждый разработчик.

Объединение нескольких строк в одну

Наверняка вам приходилось генерить одну строку из нескольких других, разделённых запятыми. При этом после последнего элемента запятой быть не должно. Знакомо? В java 8 это делается так:

Stream.of("Linux", "Windows", "Mac")
    .collect(Collectors.joining(", ")));

Мы создаём новый поток из простых строк, а затем собираем их в одну при помощи метода collect. В результате получим следующую строку:

Linux, Windows, Mac

Сгенерить N одинаковых элементов

Сгенерим три знака вопроса и вставим между ними запятые, аналогично предыдущей задаче:

Stream.generate(() -> "?")                
        .limit(3)                         
        .collect(Collectors.joining(", "))

Получим:

?, ?, ?

Работа с произвольными объектами

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

public class Person {

    private final String name;
    private final int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }


    public String getName() {
        return name;
    }


    public int getAge() {
        return age;
    }


    @Override
    public String toString() {
        return String.format("%s (%s)", name, age);
    }
}

Теперь инициализируем коллекцию, которую потом будем преобразовывать.

List<Person> persons = new ArrayList<>();
persons.add(new Person("Боб", 25));
persons.add(new Person("Алиса", 20));
persons.add(new Person("Николай Петрович", 60));

Фильтрация элементов

Выберем всех пользователей не старше 30 лет и выведем каждого из них на экран:

persons.stream()                       
        .filter(p -> p.getAge() <= 30) 
        .forEach(System.out::println); 

Обратите внимание, что Stream можно получить из любой коллекции при помощи метода stream(). Затем в методе filter используем лямбда-выражение (вместо p можно использовать любое другое имя). В качестве выражения фильтрации можно использовать абсолютно любое выражение, возвращающее тип boolean. И наконец, для каждого из оставшихся элементов мы вызываем статическую функцию println. Обратите внимание на её особую запись. Эту запись можно использовать для любого метода, принимающего один параметр.

В результате на экране увидим Боба и Алису, а вот Николаю Петровичу не повезло:

Боб (25)
Алиса (20)

Среднее значение

Подсчитаем средний возраст наших персон, используя другой коллектор:

persons.stream()                                          
        .collect(Collectors.averagingInt(Person::getAge)) 

Для метода Person.getAge опять используем сокращённую запись. В результате получим, что средний возраст составляет 35,0 лет.

Преобразование элементов


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

persons.stream()                            
        .map(p -> p.getName().toUpperCase())
        .collect(Collectors.joining(", "))  

Результат:

БОБ, АЛИСА, НИКОЛАЙ ПЕТРОВИЧ

Чтение файла в строку

Прочитать все строки текстового файла и объединить их в одну строку можно так:

Path path = Paths.get(путь_до_файла);                        
Files.lines(path, StandardCharsets.UTF_8)                    
        .collect(Collectors.joining(System.lineSeparator()));

Обратите внимание, что для объединения строк здесь используется платформенно-независимый метод System.lineSeparator(), возращающий один или два символа перевода строки в зависимости от вашей ОС.

Запись коллекции строк в файл

Похожим образом производится и запись строк в файл:

Path path = Paths.get("путь_до_файла");
Files.write(path, Arrays.asList("first line", "second line"), StandardCharsets.UTF_8);

На выходе получим файл, состоящий из двух строк.

Комментариев нет:

Отправить комментарий