Перейти к основному содержимому

Java 8 Stream skip() против limit()

· 3 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Введение

В этой короткой статье мы поговорим о методах skip() и limit() API Java Stream и выделим их сходства и различия.

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

2. Метод пропуска ()

Метод skip(n) — это промежуточная операция, которая отбрасывает первые n элементов потока . Параметр n не может быть отрицательным, и если он больше размера потока, skip() возвращает пустой поток.

Давайте посмотрим пример:

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.filter(i -> i % 2 == 0)
.skip(2)
.forEach(i -> System.out.print(i + " "));

В этом потоке мы берем четные числа потока, но пропускаем первые два. Следовательно, наш результат:

6 8 10

Когда этот поток выполняется, forEach начинает запрашивать элементы. Когда она доходит до skip() , эта операция знает, что первые два элемента должны быть отброшены, поэтому она не добавляет их в результирующий поток. После этого он создает и возвращает поток с оставшимися элементами.

Для этого операция skip() должна сохранять состояние элементов, видимых в каждый момент времени. По этой причине мы говорим, что skip() — это операция с отслеживанием состояния .

3. Метод limit ()

Метод limit(n) — еще одна промежуточная операция, которая возвращает поток не длиннее запрошенного размера . Как и прежде, параметр n не может быть отрицательным.

Давайте использовать его в примере:

Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.filter(i -> i % 2 == 0)
.limit(2)
.forEach(i -> System.out.print(i + " "));

В этом случае мы получаем только два четных числа из нашего потока int :

2 4

Как и операция skip() , limit() также является операцией с отслеживанием состояния, поскольку она должна сохранять состояние забираемых элементов.

Но в отличие от skip() , который потребляет весь поток, как только limit() достигает максимального количества элементов, он больше не потребляет элементы и просто возвращает результирующий поток. Следовательно, мы говорим, что limit() является операцией короткого замыкания .

При работе с бесконечными потоками limit() может быть очень полезен для усечения потока до конечного:

Stream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0)
.limit(10)
.forEach(System.out::println);

В этом примере мы усекаем бесконечный поток чисел до потока всего с десятью четными числами.

4. Комбинация skip() и limit()

Как мы упоминали ранее, операции пропуска и ограничения дополняют друг друга, и если мы объединим их, в некоторых случаях они могут быть очень полезными.

Давайте представим, что мы хотим изменить наш предыдущий пример, чтобы он получал четные числа партиями по десять. Мы можем сделать это, просто используя как skip() , так и limit() в одном и том же потоке:

private static List<Integer> getEvenNumbers(int offset, int limit) {
return Stream.iterate(0, i -> i + 1)
.filter(i -> i % 2 == 0)
.skip(offset)
.limit(limit)
.collect(Collectors.toList());
}

Как мы видим, с помощью этого метода мы можем довольно легко разбивать поток на страницы. Несмотря на то, что это очень упрощенная разбивка на страницы, мы можем видеть, насколько мощной она может быть при нарезке потока.

5. Вывод

В этой краткой статье мы показали сходства и различия методов skip() и limit() API Java Stream. Мы также реализовали несколько простых примеров, чтобы показать, как мы можем использовать эти методы.

Как всегда, полный исходный код примеров доступен на GitHub .