Mapa sobre colección genérica en Java 11 [duplicado]

Nov 28 2020

He estado tratando de encontrar una manera de escribir una función genérica, posiblemente sin usar genéricos, para mapear una colección.

Digamos que tengo una función A a B, me gustaría escribir una función que tome Collection<A>ay devuelva a Collection<B>. TENGA EN CUENTA que A y B no son genéricos, solo una forma de expresar un patrón general.

Lo que tengo hasta ahora es

public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
    return points.stream()
            .map(Utils::point2dToPoint)
            .collect(Collectors.toCollection(() -> points));

}

Sin embargo, obtengo un error de tipo en el .collect, porque obviamente quiero que sea la nueva colección, Collection<Point>pero no estoy seguro de cómo obtener un Proveedor para eso.

Editar: Me gustaría poder usar esta función de forma genérica: si le paso un Conjunto, obtengo un Conjunto a cambio, pero si le paso una Lista, obtengo una lista a cambio. ¿Es posible hacer esto?

Respuestas

3 dreamcrash Nov 28 2020 at 03:32

La mejor opción es no complicar demasiado y simplemente hacer:

public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
    return points.stream()
            .map(Utils::point2dToPoint)
            .collect(Collectors.toList());
}

devolver un implemento concreto de interfaz Collection( por ejemplo, Collectors.toList() ) mientras se oculta del exterior los detalles de implementación ( es decir, tener Collectionen la firma del método).

Sin embargo, puede hacer que su método sea más genérico pasándole, como Supplier, qué implementación concreta de la interfaz Collectiondesea que devuelva, es decir

 public static Collection<Point> points2dToPoints(Collection<Point2D> points, Supplier<Collection<Point>> aNew) {
        return points.stream()
                .map(Utils::point2dToPoint)
                .collect(toCollection(aNew));

De esta forma se puede pasar la Collectionimplementación concreta que se devolverá, por ejemplo:

points2dToPoints(.., ArrayList::new);
points2dToPoints(.., TreeSet::new);
2 LiveandLetLive Nov 28 2020 at 03:31

Reemplace la declaración Collectors.toCollection(() -> points)con Collectors.toList().

Manifestación:

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

class Car {
    String name;

    public Car(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Car [name=" + name + "]";
    }
}

class Book {
    Car car;

    public Book(Car car) {
        this.car = car;
    }

    public Car getCar() {
        return car;
    }
}

public class Main {
    public static void main(String[] args) {
        // Test
        Collection<Car> list = points2dToPoints(
                List.of(new Book(new Car("Toyota")), new Book(new Car("Ford")), new Book(new Car("Suzuki"))));

        list.forEach(System.out::println);
    }

    public static Collection<Car> points2dToPoints(Collection<Book> points) {
        return points.stream().map(Book::getCar).collect(Collectors.toList());    
    }
}

Salida:

Car [name=Toyota]
Car [name=Ford]
Car [name=Suzuki]