Mapa sobre colección genérica en Java 11 [duplicado]
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
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 Collection
en 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 Collection
desea 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 Collection
implementación concreta que se devolverá, por ejemplo:
points2dToPoints(.., ArrayList::new);
points2dToPoints(.., TreeSet::new);
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]