Перейти к содержимому
шпаргалка.
Esc
навигацияоткрыть⌘Jпредпросмотр
На этой странице

Stream API

Все темы Java Developer

Что такое Stream?

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

Основные характеристики и особенности Java Stream :
  1. Ленивые вычисления: Операции над потоками выполняются лениво (lazy), что означает, что элементы обрабатываются только по мере необходимости. Это позволяет оптимизировать работу с данными, избегая лишних вычислений.

  2. Функциональный стиль: Операции над потоками часто выполняются с использованием лямбда-выражений, что позволяет писать компактный и выразительный код.

  3. Операции над потоками: Stream API включает в себя разнообразные операции:

    • Промежуточные операции (intermediate operations), такие как filter, map, sorted, distinct, которые выполняются над элементами потока и возвращают новый поток.

    • Терминальные операции (terminal operations), например, forEach, collect, reduce, count, которые завершают обработку потока и возвращают результат.

  4. Пример использования:

    import java.util.Arrays;
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) {
            List<String> fruits = Arrays.asList("Apple", "Orange", "Banana", "Grapes", "Mango");
    
            // Пример использования Stream API
            long count = fruits.stream()
                               .filter(fruit -> fruit.startsWith("A"))
                               .sorted()
                               .count();
    
            System.out.println("Number of fruits starting with 'A': " + count);
        }
    }

    В приведенном примере создается поток (Stream) из списка фруктов, фильтруются только те, которые начинаются с буквы “A”, затем сортируются и подсчитывается их количество.


Что такое Optional?

Optional в Java представляет собой контейнерный объект, который может содержать или не содержать некоторое значение. Основная идея Optional заключается в том, чтобы явно обозначить, что значение может отсутствовать, и предоставить удобные методы для работы с этим возможным отсутствующим значением без необходимости в явной проверке на null.

Основные особенности Optional :
  1. Может содержать или не содержать значение: Optional может быть пустым (empty) или содержать конкретное значение (ненулевое).

  2. Предотвращение NullPointerException: Использование Optional помогает избежать NullPointerException, так как методы Optional предоставляют безопасные операции для работы с возможно отсутствующими значениями.

  3. Методы для работы с значениями:

    • isPresent(): Проверяет, содержит ли Optional значение.

    • ifPresent(Consumer<? super T> consumer): Выполняет заданное действие, если значение присутствует.

    • orElse(T other): Возвращает значение, если оно присутствует, иначе возвращает заданное значение по умолчанию.

    • orElseGet(Supplier<? extends T> supplier): Возвращает значение, если оно присутствует, иначе возвращает значение, полученное от заданного поставщика.

    • orElseThrow(Supplier<? extends X> exceptionSupplier): Возвращает значение, если оно присутствует, иначе выбрасывает исключение, полученное от заданного поставщика.

  4. Пример использования:

    import java.util.Optional;
    
    public class Main {
        public static void main(String[] args) {
            Optional<String> optionalString = Optional.of("Hello");
    
            // Проверка наличия значения и вывод его
            if (optionalString.isPresent()) {
                System.out.println("Value: " + optionalString.get());
            } else {
                System.out.println("No value present");
            }
    
            // Использование метода ifPresent для вывода значения
            optionalString.ifPresent(value -> System.out.println("Value: " + value));
    
            // Получение значения или возврат "Default" по умолчанию
            String result = optionalString.orElse("Default");
            System.out.println("Result: " + result);
    
            // Получение значения или вызов исключения, если значение отсутствует
            String value = optionalString.orElseThrow(() -> new RuntimeException("Value is absent"));
            System.out.println("Value: " + value);
        }
    }

    В приведенном примере создается Optional объект с значением "Hello". После этого демонстрируются методы isPresent(), ifPresent(), orElse() и orElseThrow() для работы с этим объектом Optional.


Какие существуют способы создания стрима?

В Java существует несколько способов создания стрима:

  1. Из коллекции: Стрим можно создать из коллекции с помощью метода stream():

    List<String> list = Arrays.asList("apple", "banana", "cherry");
    Stream<String> streamFromCollection = list.stream();
  2. Из массива: Для создания стрима из массива используется статический метод Stream.of():

    String[] array = {"apple", "banana", "cherry"};
    Stream<String> streamFromArray = Stream.of(array);
  3. Из значений (varargs): Можно создать стрим напрямую из значений с помощью Stream.of():

    Stream<String> streamOfValues = Stream.of("apple", "banana", "cherry");
  4. Из файла: Files.lines() возвращает поток, который нужно закрыть, обычно через try-with-resources. Это освобождает открытый файл даже при исключении.

    Path path = Paths.get("file.txt");
    Stream<String> lines = Files.lines(path);
  5. С помощью метода generate или iterate: Для создания бесконечных стримов используются методы Stream.generate() и Stream.iterate():

    • Stream.generate(Supplier<T> supplier): Генерирует элементы на основе заданного поставщика.

      Stream<Integer> infiniteStream = Stream.generate(() -> 1);
    • Stream.iterate(T seed, UnaryOperator<T> f): Создает стрим, начиная с заданного начального значения и применяя функцию к предыдущему элементу для получения следующего.

      Stream<Integer> numbers = Stream.iterate(0, n -> n + 2);
  6. Из регулярного выражения: Метод Pattern.splitAsStream() позволяет создать стрим из разделенных элементов строки по заданному регулярному выражению.

    Pattern pattern = Pattern.compile(",");
    Stream<String> splitStream = pattern.splitAsStream("apple,banana,cherry");

Какова цель метода filter() в стримах?

Метод filter() в Java Stream API используется для фильтрации элементов стрима на основе заданного условия. Он позволяет выбирать только те элементы, которые соответствуют заданному предикату (условию).

Основная цель метода filter() состоит в том, чтобы:
  • Уменьшить объем данных, с которыми нужно работать в дальнейших операциях.

  • Оставить только те элементы стрима, которые удовлетворяют определенному критерию или условию.

Пример использования метода filter():

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Фильтрация четных чисел
Stream<Integer> evenNumbersStream = numbers.stream()
                                          .filter(n -> n % 2 == 0);

// Сбор результата в список
List<Integer> evenNumbersList = evenNumbersStream.collect(Collectors.toList());

System.out.println(evenNumbersList); // Выведет: [2, 4, 6, 8, 10]

В этом примере filter() принимает предикат n -> n % 2 == 0, который проверяет, является ли число четным. Только числа, удовлетворяющие этому условию, проходят через фильтр и попадают в итоговый стрим evenNumbersStream.


В чем разница между Collection и Stream?

Основные различия между Collection и Stream в Java можно сформулировать следующим образом:

  1. Назначение:

    • Collection представляет собой структуру данных, которая хранит элементы и предоставляет методы для управления этими элементами (добавление, удаление, получение элементов и т.д.).

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

  2. Изменяемость:

    • Collection может быть изменяемой или предоставлять неизменяемый доступ. Collections.unmodifiableList() возвращает представление, запрещающее изменения через него, но исходный список может изменяться отдельно.

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

  3. Вычисление:

    • Collection хранит элементы в памяти, и все операции выполняются сразу после вызова метода.

    • Stream использует ленивые вычисления: операции над стримом выполняются только при вызове терминальной операции. Это позволяет оптимизировать работу с данными и избегать лишних вычислений.

  4. Использование:

    • Collection подходит для хранения и манипуляций с наборами данных в памяти.

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

Пример использования Collection и Stream :
// Пример использования Collection
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
list.add("orange"); // Добавление элемента в коллекцию

// Пример использования Stream
Stream<String> stream = list.stream();
stream.filter(s -> s.startsWith("a"))
      .forEach(System.out::println); // Вывод элементов, начинающихся с "a"

В этом примере list — это коллекция, которая хранит элементы в памяти и поддерживает операции добавления и получения элементов.

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


Для чего нужен метод collect() в стримах?

Метод collect() в Java Stream API используется для сбора элементов стрима в различные структуры данных, такие как коллекции (List, Set, Map), массивы или другие пользовательские контейнеры. Он предоставляет гибкую возможность окончательной обработки данных в стриме и преобразования их в желаемый формат.

Основные цели и преимущества метода collect() :
  1. Сбор в коллекции: Наиболее частое использование collect() — это сбор элементов стрима в коллекцию. Например, в список (toList()), множество ( toSet()), или карту (toMap()).

    List<String> list = Stream.of("apple", "banana", "cherry")
                              .collect(Collectors.toList());
  2. Группировка и агрегация: Метод collect() позволяет группировать элементы и выполнять агрегирующие операции.

    Map<Integer, List<String>> map = Stream.of("apple", "banana", "cherry")
                                          .collect(Collectors.groupingBy(String::length));
  3. Преобразование в массивы и другие структуры данных: Метод collect() также может быть использован для преобразования элементов стрима в массивы, строки и другие пользовательские контейнеры.

    String[] array = Stream.of("apple", "banana", "cherry")
                           .toArray(String[]::new);
  4. Собственные коллекции и контейнеры: Вы можете использовать collect() для сбора элементов в собственные реализации коллекций или другие пользовательские контейнеры.

Эта страница была полезной?