2015-05-21 12 views
8

Mam tu Handler klasę, która ma obsługiwać Event s pewnego typu:Czy istnieje sposób jawnego zdefiniowania typowego parametru parametru w wyrażeniu lambda?

public interface Handler<E extends Event> 
{ 
    public void handle(E event); 

    @SuppressWarnings("unchecked") 
    public default Class<E> getEventType() 
    { 
     for(Method method: this.getClass().getDeclaredMethods()) 
     { 
      if(method.getName().equals("handle")) return (Class<E>)method.getParameterTypes()[0]; 
     } 
     throw new NullPointerException("Couldn't find the 'handle' method in this handler."); 
    } 
} 

Jak widać, będzie starał domyślnie dostać rodzaj Event wracając pierwszy typ parametru metody handle() za każdym razem, gdy wykonywany jest getEventType() (w przeciwieństwie do Handler, który zwraca go jawnie). To działa prawidłowo z poniższego testu JUnit:

public static class EmptyEvent extends Event 
{ 
    public void test() { } 
} 

public static Handler<EmptyEvent> genericHandler = new Handler<EmptyEvent>() 
{ 
    @Override 
    public void handle(EmptyEvent event) 
    { 

    } 
}; 

@Test 
public void testEventGenerics() 
{ 
    //prints the name of EmptyEvent 
    System.out.println(genericHandler.getEventType()); 
} 

IntelliJ IDEA mówi mi, że mogę uprościć genericHandler do wyrażenia lambda, więc mogę to zrobić:

public static class EmptyEvent extends Event 
{ 
    public void test() { } 
} 

public static Handler<EmptyEvent> genericHandler = event -> { }; 

@Test 
public void testEventGenerics() 
{ 
    //prints the name of the base Event class 
    System.out.println(genericHandler.getEventType()); 
} 

Jednak wydruki przetestować nazwą z Event, a nie EmptyEvent.

Moje pytanie brzmi: Czy istnieje sposób wyraźnego zdefiniowania ogólnego typu parametru wyrażenia lambda?

Próbowałem zrobić coś takiego, ale to nic nie robi (również jest to błąd)

public static Handler<EmptyEvent> genericHandler = (EmptyEvent)event -> { }; 

Odpowiedz

4

Tak można określić typ parametru wyrażenia lambda:

public static Handler<EmptyEvent> genericHandler = (EmptyEvent event) -> { }; 

Ogólnie nie jest to konieczne, ponieważ jest implikowane przez kontekst. Jednak często sprawia, że ​​kod jest łatwiejszy do odczytania.

Zobacz https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27 więcej szczegółów

+0

HMM. Kompiluje i to odpowiada na pytanie, ale z jakiegoś powodu 'genericHandler.getEventType()' nadal zwraca nazwę 'Event'. Czy masz jakiś pomysł, dlaczego? – octopod

+0

@Octopod prawdopodobnie dlatego, że polegasz na tym, że różne metody zwracają 'getDeclaredMethods', co jest nie-nie. – immibis

+0

@immibis z wyjątkiem tego, że jestem pewien, że istnieje tylko jedna metoda 'handle()' (ta którą zdefiniowałem), nie ma tam? Czy mówisz, że jest też 'uchwyt (Event)'? – octopod

1

Robisz założenia o klasie obiektu, który lambda ocenia się, i nie sądzę, te założenia są prawidłowe. Wystarczające jest, że N zastępuje metodę handle() z Handler, a w czasie działania, A handle() sposób, że wykonuje Event jest wystarczająca, aby zastąpić handle() Od Handler, który po usunięciu trwa Event. Nigdzie nie jest zagwarantowane, że lambda musi mieć metodę handle(), która może być introspekowana, aby powiedzieć, że zajmuje EmptyEvent.

0

Poniższe zmienne mogą wskazywać na ten sam obiekt!

Handler<EventA> handlerA = event -> { }; 
Handler<EventB> handlerB = event -> { }; 

Consumer<String> consumer1 = string -> {} 
Consumer<Integer> consumer2 = integer-> {} 

Nie można właściwie określić dokładnego typu środowiska wykonawczego wyrażenia lambda; jedyną gwarancją jest to, że ciało lambda działa w czasie wykonywania.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.4

[runtime] treści metody ma tę efekt oceniania ciału lambda

Powiązane problemy