2017-11-01 40 views
7

Załóżmy Mam metodę z następującym podpisem:typu bezpiecznie utworzyć instancję Function zostać przekazany do Comparator.comparing()

<T, U extends Comparable<? super U>> Comparator<T> method(Map<String, Function<? super T, ? extends U>> comparatorFunctionMap) 

Metoda akceptuje mapę funkcji (z kluczami tekstowymi) i tworzy w wyniku tego powstaje Comparator<T> (nie jest ważne jak). Wartości map są instancjami Function<? super T, ? extends U>, dzięki czemu można je bezpośrednio przekazać do Comparator.comparing().

Jak zapełnić tę mapę w bezpieczny sposób? Powiedzmy, że mam klasę Person z atrybutami name i age (i pobierającymi je dla nich).

Kiedy należy wykonać następujące czynności:

Map<String, Function<? super Person, ? extends Comparable>> map1 = new HashMap<>(); 
map1.put("name", Person::getName); 
method(map1); 

otrzymuję ostrzeżenie na linii 1 i 3. Jeśli próbuję to zamiast, na przykład:

Map<String, Function<? super Person, ? extends Comparable<?>>> map2 = new HashMap<>(); 
map2.put("name", Person::getName); 
method(map2); 

Trzecia linia jest błąd kompilacji .

Czy istnieje sposób na bezpieczne wykonanie tego typu?

+0

Nie otrzymuję żadnego ostrzeżenia przy użyciu pierwszego fragmentu (surowe porównywalne). – Eran

+1

Czy potrzebujesz funkcji na mapie, aby móc zwrócić więcej niż jeden typ? np. czy ta sama mapa musi zawierać funkcję "Function " i "Function "? –

+0

@MikeStrobel: Tak, chodziło o to, aby pozwolić różnym porównywalnym typom (przynajmniej ciągi i liczby, ale być może także innym) na mapie. Teraz widzę, że to główny problem. – Ondra

Odpowiedz

2

Jeśli chcesz mieć możliwość dodania zarówno Person::getName, jak i Person::getAge na mapie, nie będziesz w stanie użyć proponowanej metody, ponieważ nie ma U, która jest nadtypem zarówno String, Integer i Comparable.

Zasadniczo twoja mapa to Map<String, Function<T, Comparable<?>>, ponieważ elementy porównawcze nie są ze sobą powiązane.

Nie sądzę, że można obejść go bez używania surowych typów, które mogą wyglądać jak poniżej. Zwróć uwagę, że nadal masz bezpieczeństwo typu (musisz podać Comparable na mapie).

static void m() { 
    Map<String, Function<Person, Comparable<?>>> map = new HashMap<>(); 
    map.put("name", Person::getName); 
    map.put("age", Person::getAge); 
    Comparator<Person> c = method(map); 
} 


@SuppressWarnings(value = {"unchecked", "rawtypes"}) 
static <T> Comparator<T> method(String name, Map<String, Function<T, Comparable<?>>> comparatorFunctionMap) { 
    Function f = (Function) comparatorFunctionMap.get("age"); 
    Comparator<T> c = Comparator.comparing(f); 
    return c; 
} 

Jedyny (chyba) ograniczeniem jest to, że pod względem technicznym, można przekazać dziwne klasa powiedzieć Weird implements Comparable<String> że prawdopodobnie spowodować błąd wykonania.

+0

Zakładam, że 'getName()' zwraca 'String', który nie pasuje do wiązania' Porównywalna '. –

+0

@MikeStrobel masz rację, edytowałem. – assylias

+0

@assylias: Dzięki, miałem wrażenie, że problem polega na próbach dopasowania funkcji, które zwracają różne porównywalne typy do wspólnej kolekcji, ale nie mogą jej poprawnie wyrazić. – Ondra