Métodos da Stream API em Java: skip e limit
A Stream API oferece dois métodos intermediários, skip
e limit
, que são ferramentas fundamentais para fatiar um fluxo de dados. Quando utilizados em conjunto, eles se tornam a base para implementar de forma elegante a lógica de paginação para coleções em memória.
O método skip(long n)
retorna um novo stream que descarta os primeiros n
elementos do stream original.
O método limit(long n)
retorna um novo stream que é truncado para não ter mais do que n
elementos. Esta é uma operação de curto-circuito; assim que o limite de n
elementos é atingido, o processamento dos elementos restantes do stream é interrompido, otimizando o desempenho.
Combinando skip e limit
A verdadeira força desses métodos aparece quando são combinados. A estratégia é usar skip
para "pular" até o início da página desejada e, em seguida, usar limit
para selecionar apenas os itens que compõem essa página.
import java.util.stream.Stream;
// ...
Stream<String> phoneStream = Stream.of(
"iPhone 15", "Pixel 8", "Galaxy S24", "Xiaomi 14", "OnePlus 12"
);
phoneStream.skip(1) // Descarta o primeiro elemento ("iPhone 15")
.limit(2) // Pega os próximos 2 elementos
.forEach(s -> System.out.println(s));
O resultado no console será:
Pixel 8 Galaxy S24
Importante: Paginação em Memória vs. Banco de Dados
É crucial entender que esta abordagem com skip
e limit
é ideal para processar coleções que já estão na memória da aplicação.
Se você precisa paginar um grande volume de dados vindo de um banco de dados, a abordagem correta é delegar a paginação ao próprio banco através da consulta SQL (usando cláusulas como LIMIT
e OFFSET
). Puxar milhões de registros do banco para a memória da aplicação para depois usar skip
e limit
é extremamente ineficiente e pode causar problemas de performance e consumo de memória.
Exemplo Prático: Implementando um Sistema de Paginação
Vamos criar um programa robusto que simula a navegação por páginas em uma lista de produtos.
import java.util.List;
import java.util.Scanner;
public class PaginationExample {
public static void main(String[] args) {
List<String> phones = List.of(
"iPhone 15", "Pixel 8", "Galaxy S24", "Xiaomi 14", "OnePlus 12",
"Xperia 1 V", "ROG Phone 8", "Redmi Note 13", "Zenfone 10", "Nothing Phone (2)"
);
int pageSize = 3; // Define que cada página terá 3 elementos
// Calcula o número total de páginas
long totalPages = (long) Math.ceil((double) phones.size() / pageSize);
try (Scanner scanner = new Scanner(System.in)) {
while (true) {
System.out.printf("\nTotal de páginas: %d. Digite o número da página (ou < 1 para sair):\n", totalPages);
int page = scanner.nextInt();
if (page < 1) {
System.out.println("Encerrando o programa.");
break;
}
if (page > totalPages) {
System.out.println("Página inválida. Por favor, tente novamente.");
continue;
}
// A fórmula para pular os elementos das páginas anteriores
long itemsToSkip = (long)(page - 1) * pageSize;
System.out.printf("--- Página %d ---\n", page);
phones.stream()
.skip(itemsToSkip)
.limit(pageSize)
.forEach(System.out::println);
}
}
}
}
Neste exemplo aprimorado:
- Calculamos o número total de páginas para fornecer mais contexto ao usuário.
- Validamos a entrada do usuário, informando se a página solicitada não existe.
- Utilizamos um
try-with-resources
para garantir que oScanner
seja fechado corretamente.
A interação com o programa se torna mais informativa e segura:
Total de páginas: 4. Digite o número da página (ou < 1 para sair): 2 --- Página 2 --- Xiaomi 14 OnePlus 12 Xperia 1 V Total de páginas: 4. Digite o número da página (ou < 1 para sair): 5 Página inválida. Por favor, tente novamente.
Resumo
- O método
skip(n)
descarta osn
primeiros elementos de um stream. - O método
limit(n)
restringe o stream a um máximo den
elementos e é uma operação de curto-circuito. - A combinação
stream.skip(...).limit(...)
é o padrão ideal para implementar paginação em coleções em memória. - Para grandes volumes de dados em bancos de dados, a paginação deve ser feita na consulta (e.g., SQL), não na aplicação Java.