Mapear coleção genérica em Java 11 [duplicado]
Tenho tentado encontrar uma maneira de escrever uma função genérica - possivelmente sem usar genéricos - para mapear uma coleção.
Digamos que eu tenha uma função de A a B, gostaria de escrever uma função que receba a Collection<A>
e retorne a Collection<B>
. NOTE que A e B não são genéricos, apenas uma forma de expressar um padrão geral.
O que eu tenho até agora é
public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(Collectors.toCollection(() -> points));
}
No entanto, recebo um erro de tipo no .collect
, porque obviamente quero que a nova coleção seja, Collection<Point>
mas não tenho certeza de como conseguir um fornecedor para isso.
Edit: gostaria de poder usar esta função de uma forma genérica: se passo um Set, recebo um Set em troca, mas se passo uma List, recebo uma lista de volta. é mesmo possível fazer isso?
Respostas
A melhor opção é não complicar e simplesmente fazer:
public static Collection<Point> points2dToPoints(Collection<Point2D> points) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(Collectors.toList());
}
retornar um implemento concreto de interface Collection
( por exemplo, Collectors.toList()
) enquanto esconde de fora os detalhes de implementação (por exemplo , tendo Collection
na assinatura do método).
Você pode, no entanto, tornar seu método mais genérico, passando para ele - como Supplier
- qual implementação concreta da interface Collection
você deseja que ele retorne, a saber
public static Collection<Point> points2dToPoints(Collection<Point2D> points, Supplier<Collection<Point>> aNew) {
return points.stream()
.map(Utils::point2dToPoint)
.collect(toCollection(aNew));
Desta forma você pode passar a Collection
implementação concreta que será retornada, por exemplo:
points2dToPoints(.., ArrayList::new);
points2dToPoints(.., TreeSet::new);
Substitua a declaração Collectors.toCollection(() -> points)
por Collectors.toList()
.
Demo:
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());
}
}
Resultado:
Car [name=Toyota]
Car [name=Ford]
Car [name=Suzuki]