2016-11-09 39 views
8

Próbuję uporządkować List pracowników imieniem ówczesnego wieku przy użyciu Java8 Comparator, Stworzyłem poniżej Comparator ale daje mi błąd kompilatoraporównywania i thenComparing daje błąd kompilacji

Type mismatch: cannot convert from Comparator<Object> to <unknown>

Comparator<String> c = Comparator.comparing(s -> s.split("\\s+")[0]) 
      .thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); //compile error 

ale działa, jeśli jednoznacznie określę typ

Comparator<String> c = Comparator.<String, String> comparing(s -> s.split("\\s+")[0]) 
      .thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); //works 

lub przez utworzenie dwóch Compartor S i łańcucha

Comparator<String> name = Comparator.comparing(s -> s.split("\\s+")[0]); 
    Comparator<String> age = Comparator.comparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); 
    Comparator<String> cc = name.thenComparing(age); //works 

mam określony typ Comparator<String> na lewej stronie, ale dlaczego auto typu wnioskowanie nie jest znalezienie odpowiedniego rodzaju i spodziewa się określić jednoznacznie.

Czy ktoś może to wyjaśnić?

Oto kod

String[] arr = { "alan 25", "mario 30", "alan 19", "mario 25" }; 
    Comparator<String> c = Comparator.<String, String> comparing(s -> s.split("\\s+")[0]) 
      .thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); 
    List<String> sorted = Arrays.stream(arr).sorted(c).collect(Collectors.toList()); 
    System.out.println(sorted); 

wyjście

[alan 19, alan 25, mario 25, mario 30] 
+0

Nie jestem ekspertem od generycznego typu wnioskowania, ale zgaduję, to jest po prostu „zbyt dużo automatycznego wnioskowania”. Prawdopodobnie nie jest w stanie określić typu metody "comparing()", ponieważ nie ma ona żadnego typu do "zakotwiczenia", w przeciwieństwie do metody łańcuchowej, w której jawnie podajesz typowi wynik porównania () '. Niezależnie od tego, myślę, że byłoby bardziej czytelne napisanie własnego "Komparatora" i wywołanie tylko raz "podziału". Nie ma nagrody za ściskanie kodu w najmniejszej możliwej linii. – ajb

+1

Typowanie celu nie działa poprzez powiązane wywołania metod, zobacz [tutaj] (http://stackoverflow.com/a/28834656/2711488) i [tutaj] (http://stackoverflow.com/a/26883991/2711488) i [tutaj] (http://stackoverflow.com/a/31383947/2711488). Możesz jednak po prostu użyć 'Comparator.comparing (s -> s.replaceFirst (" \\ s + "," "))' zamiast swojego komparatora dwuetapowego, a wynik będzie taki sam ... – Holger

+0

'Comparator.comparing ((String s) -> s.split ("\\ s +") [0]). ThenComparingInt (s -> Integer.parseInt (s.split ("\\ s +") [1])) 'działa, ale dlaczego ten' String' jest wymagany, może wywnioskować z 'Komparator ', czy jest to ograniczenie w wnioskowaniu typu? BTW przy użyciu 'java version" 1.8.0_60 "' – Saravana

Odpowiedz

2

Java musi znać rodzaj wszystkich zmiennych. W wielu lambdach może wywnioskować typ, ale w twoim pierwszym fragmencie kodu nie może odgadnąć typu s. Myślę, że średnia sposobem rozwiązania tego problemu byłoby zadeklarować go wyraźnie:

Comparator<String> c = Comparator.comparing((String s) -> s.split("\\s+")[0]) 
      .thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); 

Jeśli spojrzeć na this answer, ma podobną deklarację typu w argumencie do Comparator.comparing().

Twoja metoda, jawnie podając argumenty typu comparing(), oczywiście też działa.

Dla drugiej metody, deklarując dwa komparatory, jestem przekonany, że w tym przypadku Java może wywnioskować z String po lewej stronie przypisania, tak jak w konwencjonalnym List <String> = new ArrayList<>();. Kiedy w tym samym wyrażeniu wywołasz thenComparing(), Java nie może zobaczyć, że typ z lewej strony jest istotny. Byłoby trochę jak int size = new ArrayList<>().size(); To działa zbyt:

Comparator<String> name = Comparator.comparing(s -> s.split("\\s+")[0]); 
    Comparator<String> c = name.thenComparingInt(s -> Integer.parseInt(s.split("\\s+")[1])); 
+1

@ ole-vv Comparator.comparing ((String s) -> s.split ("\\ s +") [0]). ThenComparingInt (s -> Integer.parseInt (s.split ("\\ s +") [1])) działa, ale dlaczego ten ciąg jest wymagane, może wywnioskować z Komparatora , czy jest to ograniczenie w wnioskowaniu typu? BTW przy użyciu wersji java "1.8.0_60" – Saravana

+2

Jak można to wywnioskować? Wiesz, że 'thenComparing()' powinien zwrócić 'Komparator ' (aby zmieścić się po lewej stronie przypisania), dlatego 'porównywanie()' musi zwrócić 'Komparator ', dlatego 's' musi być 'String'. Kompilator nie przechodzi przez tak wiele kroków rozumowania. Tak, jest to ograniczenie w wnioskowaniu typu, ale uważam, że jest to ograniczenie wprowadzone celowo, ponieważ w przeciwnym razie zasady byłyby zbyt skomplikowane i programiści nie zrozumieliby ich. To jest moje najlepsze przypuszczenie. –

+1

Największym problemem jest to, że docelowe pisanie przez powiązane wywołania mogło zmienić dostępne metody dla późniejszego wywołania, które było używane do określenia poprzedniego "typu celu", tj. Z 'foo (x) .bar (y)', powrót typ 'foo (x)' określa, czy i jakie metody 'bar (...)' są dostępne, ale zastosowanie typowania celu do 'foo (x)' zależy od faktycznie wybranej metody 'bar (...)'. – Holger