CodeGym /Cursos /JAVA 25 SELF /Transformação de coleções

Transformação de coleções

JAVA 25 SELF
Nível 28 , Lição 1
Disponível

1. Transformação de elementos de coleções

Em programação, uma das operações mais frequentes — transformação de coleção: temos uma coleção de dados de um tipo e, com base nela, precisamos criar uma nova coleção de outro tipo. Por exemplo, a partir de uma lista de objetos do tipo User obter a lista de seus nomes (String), ou a partir de uma lista de números — a lista de seus quadrados.

A maneira mais fundamental e compreensível em Java é usar a abordagem imperativa, isto é, o laço for comum (muitas vezes — for-each).

Exemplo: de uma lista de strings obter a lista de seus comprimentos

Suponha que temos uma lista de nomes de cidades:

List<String> cities = List.of("Londres", "Paris", "Tóquio", "Nova York");

Nossa tarefa é criar uma nova lista que contenha o comprimento de cada nome. O resultado final deve ser: [7, 5, 6, 9].

Solução com o laço for:

import java.util.ArrayList;
import java.util.List;

public class CollectionTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londres", "Paris", "Tóquio", "Nova York");
        List<Integer> lengths = new ArrayList<>(); // Criamos uma nova lista vazia para o resultado

        for (String city : cities) {
            // Para cada elemento de cities calculamos seu comprimento...
            int length = city.length();
            // ...e adicionamos esse resultado à nova lista
            lengths.add(length);
        }

        System.out.println(lengths); // Irá imprimir: [7, 5, 6, 9]
    }
}

Começamos criando uma nova coleção vazia para os resultados — a transformação não altera a coleção original. Para percorrer a coleção original, usamos um laço for-each e, dentro dele, aplicamos a lógica necessária (length()) a cada elemento, e adicionamos o resultado à nova lista por meio de add.

2. Transformação de objetos

Frequentemente trabalhamos com tipos de dados mais complexos. Suponha que temos a classe Product e precisamos obter a lista de seus nomes (ou preços).

public class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

Agora, tendo uma lista de produtos, vamos obter a lista de seus nomes:

import java.util.ArrayList;
import java.util.List;

public class ProductExample {
    public static void main(String[] args) {
        List<Product> products = List.of(
            new Product("Notebook", 1200.0),
            new Product("Mouse", 25.5),
            new Product("Teclado", 75.0)
        );

        // Criamos uma nova lista para os nomes
        List<String> productNames = new ArrayList<>();

        for (Product product : products) {
            // Para cada objeto Product obtemos seu nome
            productNames.add(product.getName());
        }

        System.out.println(productNames); // Irá imprimir: [Notebook, Mouse, Teclado]
    }
}

A lógica é a mesma: iteramos pela coleção original, aplicamos a cada elemento o método necessário (por exemplo, getName()) e adicionamos o resultado à nova coleção.

3. Trabalhando com coleções aninhadas

Considere o caso de uma lista de listas: vários departamentos, em cada um — sua própria lista de funcionários. A tarefa é obter uma única lista (“plana”) de todos os funcionários.

Exemplo: união de listas de funcionários

List<List<String>> departments = List.of(
    List.of("Anna", "Boris"),
    List.of("Viktoriya", "Gleb", "Dmitriy"),
    List.of("Elena")
);

Queremos obter uma lista única: [Anna, Boris, Viktoriya, Gleb, Dmitriy, Elena].

Modo 1: usando o método addAll()

import java.util.ArrayList;
import java.util.List;

public class NestedCollectionExample {
    public static void main(String[] args) {
        List<List<String>> departments = List.of(
            List.of("Anna", "Boris"),
            List.of("Viktoriya", "Gleb", "Dmitriy"),
            List.of("Elena")
        );

        List<String> allEmployees = new ArrayList<>();

        // Iteramos por cada lista (departamento)
        for (List<String> department : departments) {
            // Adicionamos todos os elementos da lista atual à lista geral
            allEmployees.addAll(department);
        }

        System.out.println(allEmployees); // [Anna, Boris, Viktoriya, Gleb, Dmitriy, Elena]
    }
}

Modo 2: laço aninhado — o mesmo, mas “na mão”:

List<List<String>> departments = List.of(...);
List<String> allEmployees = new ArrayList<>();

for (List<String> department : departments) { // Laço externo por departamentos
    for (String employee : department) {      // Laço interno por funcionários
        allEmployees.add(employee);
    }
}

System.out.println(allEmployees);

Ambos os modos são equivalentes no resultado. O método addAll() basicamente encapsula a lógica do laço aninhado e torna o código mais curto.

4. Casos complexos e transformações condicionais

Às vezes a transformação precisa ser feita apenas para elementos que satisfazem uma condição. Por exemplo, obter a lista de nomes de cidades que começam com a letra "N" e pegar seus comprimentos. Aqui combinamos filtragem e transformação: if + chamada de método (length()).

import java.util.ArrayList;
import java.util.List;

public class ConditionalTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londres", "Paris", "Tóquio", "Nova York", "Nurembergue");
        List<Integer> lengths = new ArrayList<>();

        for (String city : cities) {
            // Primeiro verificamos a condição
            if (city.startsWith("N")) {
                // Se a condição for satisfeita, aplicamos a transformação
                lengths.add(city.length());
            }
        }

        System.out.println(lengths); // Irá imprimir: [9, 11]
    }
}

O padrão é: dentro do laço, primeiro filtramos o elemento por uma condição (startsWith, comparação, verificação de faixa etc.), depois aplicamos a transformação necessária e colocamos o resultado na nova lista.

5. Erros comuns e armadilhas

Erro nº 1: modificar a coleção original durante a iteração. Um erro comum é tentar adicionar/remover elementos da coleção de origem diretamente no laço for-each. Isso leva a erros e comportamento imprevisível. Solução: sempre crie uma nova lista para os resultados e a preencha.

Erro nº 2: conversão de tipos incorreta. Se você trabalha com coleções “cruas” (por exemplo, via Object) e faz cast dos elementos para um tipo incorreto, terá ClassCastException. Use generics (List<T>) e fique atento às assinaturas.

Erro nº 3: uso ineficiente de recursos. Para coleções muito grandes, a criação constante de novas listas e a cópia de elementos pode impactar memória e tempo. Na maioria das tarefas do dia a dia isso é aceitável, mas ao processar grandes volumes de dados, considere a complexidade e, se necessário, otimize a abordagem.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION