Mapuj kolekcję ogólną w Javie 11 [duplikat]

Nov 28 2020

Próbowałem znaleźć sposób na napisanie funkcji ogólnej - być może bez użycia typów ogólnych - do mapowania kolekcji.

Powiedzmy, że mam funkcję od A do B, chciałbym napisać funkcję, która przyjmuje a Collection<A>i zwraca a Collection<B>. PAMIĘTAJ, że A i B nie są rodzajami, a jedynie sposobem wyrażenia ogólnego wzorca.

To, co mam do tej pory, to

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

}

Jednak w tagu pojawia się błąd typu .collect, ponieważ oczywiście chcę, aby nowa kolekcja była, Collection<Point>ale nie jestem pewien, jak uzyskać do tego dostawcę?

Edycja: Chciałbym móc używać tej funkcji w sposób ogólny: jeśli przekażę jej zestaw, otrzymam w zamian zestaw, ale jeśli przekażę listę, otrzymam w zamian listę. czy jest to w ogóle możliwe?

Odpowiedzi

3 dreamcrash Nov 28 2020 at 03:32

Najlepszą opcją jest unikanie nadmiernych komplikacji i po prostu:

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

zwracanie konkretnej implementacji interfejsu Collection( np. Collectors.toList() ) z jednoczesnym ukryciem od zewnątrz szczegółów implementacji ( czyli posiadaniem Collectionw metodzie sygnatury).

Możesz jednak uczynić swoją metodę bardziej ogólną, przekazując do niej - jako Supplier- konkretną implementację interfejsu, Collectionktórą chcesz, aby zwracała, a mianowicie

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

W ten sposób możesz przekazać konkretną Collectionimplementację, która zostanie zwrócona, na przykład:

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

Wymień oświadczenie Collectors.toCollection(() -> points)z Collectors.toList().

Próbny:

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());    
    }
}

Wynik:

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