---
title: Stream API
seo:
  title: Stream API — Java Developer
  description: Тема «Stream API» для собеседования Java Developer. Что такое Stream? Что такое Optional?
---

[Все темы Java Developer](/java-developer)

## <strong>Что такое</strong> <code>Stream</code><strong>?</strong> [#q-14bee738d69b81ac9df9e964917760b3]

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

<strong>Основные характеристики и особенности</strong> <code>Java Stream</code>
<strong>&#58;</strong>

{/* prettier-ignore */}
1. <strong>Ленивые вычисления</strong>&#58; Операции над потоками выполняются лениво (lazy), что означает, что элементы обрабатываются только по мере необходимости. Это позволяет оптимизировать работу с данными, избегая лишних вычислений.

1. <strong>Функциональный стиль</strong>&#58; Операции над потоками часто выполняются с использованием лямбда-выражений, что позволяет писать компактный и выразительный код.

1. <strong>Операции над потоками</strong>&#58; Stream API включает в себя разнообразные операции&#58;

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

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

1. <strong>Пример использования</strong>&#58;

    ```java
    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);
        }
    }
    ```

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

:::note[Ссылки для изучения]

1. [Stream API в Java](https://javarush.com/groups/posts/2203-stream-api)
   :::

---

## <strong>Что такое</strong> <code>Optional</code><strong>?</strong> [#q-14bee738d69b8122b06fd59e6710edcc]

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

<strong>Основные особенности</strong> <code>Optional</code>
<strong>&#58;</strong>

{/* prettier-ignore */}
1. <strong>Может содержать или не содержать значение</strong>&#58; <code>Optional</code> может быть пустым (<code>empty</code>) или содержать конкретное значение (ненулевое).

1. <strong>Предотвращение NullPointerException</strong>&#58; Использование <code>Optional</code> помогает избежать <code>NullPointerException</code>, так как методы <code>Optional</code> предоставляют безопасные операции для работы с возможно отсутствующими значениями.

1. <strong>Методы для работы с значениями</strong>&#58;

    - <code>isPresent&#40;&#41;</code>&#58; Проверяет, содержит ли <code>Optional</code> значение.

    - <code>ifPresent&#40;Consumer&#60;&#63; super T&#62; consumer&#41;</code>&#58; Выполняет заданное действие, если значение присутствует.

    - <code>orElse&#40;T other&#41;</code>&#58; Возвращает значение, если оно присутствует, иначе возвращает заданное значение по умолчанию.

    - <code>orElseGet&#40;Supplier&#60;&#63; extends T&#62; supplier&#41;</code>&#58; Возвращает значение, если оно присутствует, иначе возвращает значение, полученное от заданного поставщика.

    - <code>orElseThrow&#40;Supplier&#60;&#63; extends X&#62; exceptionSupplier&#41;</code>&#58; Возвращает значение, если оно присутствует, иначе выбрасывает исключение, полученное от заданного поставщика.

1. <strong>Пример использования</strong>&#58;

    ```java
    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);
        }
    }
    ```

    В приведенном примере создается <code>Optional</code> объект с значением <code>&#34;Hello&#34;</code>. После этого демонстрируются методы <code>isPresent&#40;&#41;</code>, <code>ifPresent&#40;&#41;</code>, <code>orElse&#40;&#41;</code> и <code>orElseThrow&#40;&#41;</code> для работы с этим объектом <code>Optional</code>.

:::note[Ссылки для изучения]

1. [Будьте осторожны с Optional в Java](https://javarush.com/groups/posts/3614-kofe-breyk-97-budjhte-ostorozhnih-s-metodom-java-optional-kak-otobrazhatjh-i-summirovatjh-ehlem)
   :::

---

## <strong>Какие существуют способы создания стрима?</strong> [#q-14bee738d69b81188de9f1757ebbf0be]

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

{/* prettier-ignore */}
1. <strong>Из коллекции</strong>&#58; Стрим можно создать из коллекции с помощью метода <code>stream&#40;&#41;</code>&#58;

    ```java
    List<String> list = Arrays.asList("apple", "banana", "cherry");
    Stream<String> streamFromCollection = list.stream();
    ```

1. <strong>Из массива</strong>&#58; Для создания стрима из массива используется статический метод <code>Stream&#46;of&#40;&#41;</code>&#58;

    ```java
    String[] array = {"apple", "banana", "cherry"};
    Stream<String> streamFromArray = Stream.of(array);
    ```

1. <strong>Из значений (</strong><code>varargs</code><strong>)</strong>&#58; Можно создать стрим напрямую из значений с помощью <code>Stream&#46;of&#40;&#41;</code>&#58;

    ```java
    Stream<String> streamOfValues = Stream.of("apple", "banana", "cherry");
    ```

1. Из файла&#58; Files.lines() возвращает поток, который нужно закрыть, обычно через try-with-resources. Это освобождает открытый файл даже при исключении.

    ```java
    Path path = Paths.get("file.txt");
    Stream<String> lines = Files.lines(path);
    ```

1. <strong>С помощью метода</strong> <code>generate</code> <strong>или</strong> <code>iterate</code>&#58; Для создания бесконечных стримов используются методы <code>Stream&#46;generate&#40;&#41;</code> и <code>Stream&#46;iterate&#40;&#41;</code>&#58;

    - <code>Stream&#46;generate&#40;Supplier&#60;T&#62; supplier&#41;</code>&#58; Генерирует элементы на основе заданного поставщика.

        ```java
        Stream<Integer> infiniteStream = Stream.generate(() -> 1);
        ```

    - <code>Stream&#46;iterate&#40;T seed&#44; UnaryOperator&#60;T&#62; f&#41;</code>&#58; Создает стрим, начиная с заданного начального значения и применяя функцию к предыдущему элементу для получения следующего.

        ```java
        Stream<Integer> numbers = Stream.iterate(0, n -> n + 2);
        ```

1. <strong>Из регулярного выражения</strong>&#58; Метод <code>Pattern&#46;splitAsStream&#40;&#41;</code> позволяет создать стрим из разделенных элементов строки по заданному регулярному выражению.

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

:::note[Ссылки для изучения]

1. [Stream API в Java](https://javarush.com/groups/posts/2203-stream-api)
   :::

---

## <strong>Какова цель метода</strong> <code>filter&#40;&#41;</code> <strong>в стримах?</strong> [#q-14bee738d69b81bf9cd8df8dad5ce14c]

Метод <code>filter&#40;&#41;</code> в Java Stream API используется для фильтрации элементов стрима на основе заданного условия. Он позволяет выбирать только те элементы, которые соответствуют заданному предикату (условию).

<strong>Основная цель метода</strong> <code>filter&#40;&#41;</code>
<strong>состоит в том, чтобы&#58;</strong>

- Уменьшить объем данных, с которыми нужно работать в дальнейших операциях.

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

Пример использования метода <code>filter&#40;&#41;</code>&#58;

```java
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]
```

В этом примере <code>filter&#40;&#41;</code> принимает предикат <code>n &#45;&#62; n &#37; 2 &#61;&#61; 0</code>, который проверяет, является ли число четным. Только числа, удовлетворяющие этому условию, проходят через фильтр и попадают в итоговый стрим <code>evenNumbersStream</code>.

:::note[Ссылки для изучения]

1. [Stream API в Java](https://javarush.com/groups/posts/2203-stream-api)
   :::

---

## <strong>В чем разница между</strong> <code>Collection</code> <strong>и</strong> <code>Stream</code><strong>?</strong> [#q-14bee738d69b81648512d4b617e3cd33]

Основные различия между <code>Collection</code> и <code>Stream</code> в Java можно сформулировать следующим образом&#58;

{/* prettier-ignore */}
1. <strong>Назначение</strong>&#58;

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

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

1. <strong>Изменяемость</strong>&#58;

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

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

1. <strong>Вычисление</strong>&#58;

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

    - <code>Stream</code> использует ленивые вычисления&#58; операции над стримом выполняются только при вызове терминальной операции. Это позволяет оптимизировать работу с данными и избегать лишних вычислений.

1. <strong>Использование</strong>&#58;

    - <code>Collection</code> подходит для хранения и манипуляций с наборами данных в памяти.

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

<strong>Пример использования</strong> <code>Collection</code> <strong>и</strong>
<code>Stream</code>
<strong>&#58;</strong>

```java
// Пример использования 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"
```

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

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

:::note[Ссылки для изучения]

1. [Stream API в Java](https://javarush.com/groups/posts/2203-stream-api)
   :::

---

## <strong>Для чего нужен метод</strong> <code>collect&#40;&#41;</code> <strong>в стримах?</strong> [#q-14bee738d69b812b8be1e1310f34dbd6]

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

<strong>Основные цели и преимущества метода</strong>
<code>collect&#40;&#41;</code>
<strong>&#58;</strong>

1. <strong>Сбор в коллекции</strong>&#58; Наиболее частое использование
   <code>collect&#40;&#41;</code> — это сбор элементов стрима в коллекцию.
   Например, в список (<code>toList&#40;&#41;</code>), множество (
   <code>toSet&#40;&#41;</code>), или карту (<code>toMap&#40;&#41;</code>).

   ```java
   List<String> list = Stream.of("apple", "banana", "cherry")
                             .collect(Collectors.toList());
   ```

1. <strong>Группировка и агрегация</strong>&#58; Метод
   <code>collect&#40;&#41;</code> позволяет группировать элементы и выполнять
   агрегирующие операции.

   ```java
   Map<Integer, List<String>> map = Stream.of("apple", "banana", "cherry")
                                         .collect(Collectors.groupingBy(String::length));
   ```

1. <strong>Преобразование в массивы и другие структуры данных</strong>&#58;
   Метод <code>collect&#40;&#41;</code> также может быть использован для
   преобразования элементов стрима в массивы, строки и другие пользовательские
   контейнеры.

   ```java
   String[] array = Stream.of("apple", "banana", "cherry")
                          .toArray(String[]::new);
   ```

1. <strong>Собственные коллекции и контейнеры</strong>&#58; Вы можете
   использовать <code>collect&#40;&#41;</code> для сбора элементов в собственные
   реализации коллекций или другие пользовательские контейнеры.

:::note[Ссылки для изучения]

1. [Stream API в Java](https://javarush.com/groups/posts/2203-stream-api)
   :::
