2015-11-13 6 views
8

Ich habe gerade ein schnelles Experiment in Eclipse durchgeführt.Sind Stack-Traces weniger navigierbar, wenn Methodenverweise vs Lambdas verwendet werden?

public class StackTractTest { 

    static class Nasty { 
    public Integer toInt() { 
     if (1 == 1) throw new RuntimeException(); 
     return 1; 
    } 
    } 

    @Test 
    public void methodReference() { 
    Stream.of(new Nasty()) 
     .map(Nasty::toInt) 
     .findFirst(); 
    } 

    @Test 
    public void lambda() { 
    Stream.of(new Nasty()) 
     .map(n -> n.toInt()) 
     .findFirst(); 
    } 

} 

Wenn das Verfahren Verweis Test fehlschlägt, beginnt die Spur

java.lang.RuntimeException 
    at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11) 
    at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source) 
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) 

Es gibt keine Bezugnahme auf die Linie, auf der wieder die Methode Referenz obwohl das Ende der Spur verwendet wird (nicht dargestellt) verbindet sich zurück zur Linie mit findFirst an.

Während die lamdba stacktrace beginnt

java.lang.RuntimeException 
    at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11) 
    at com.example.StackTractTest.lambda$0(StackTractTest.java:26) 
    at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source) 
    at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) 

Welche korrekt das Lambda identifiziert auf der Leitung verwendet wurde 26.

Ist dies eine Besonderheit des Eclipse-Compiler oder ist dies ein genereller Nachteil Verfahren Referenzen verwenden, sollte bei der Wahl zwischen ihnen und einem Lambda berücksichtigt werden?

+2

Nein, das kommt von Java. Sie arbeiten an der Verbesserung der Stack-Trace-Erfahrung –

+1

Ich habe nie gehört, dass ein Entwickler für eine längere Stack-Spur fragt, bevor ... – Holger

Antwort

4

Nein, so ist es derzeit implementiert.

a paper unter Angabe von Brian Goetz über die Übersetzung von Lambda-Ausdrücke geschrieben:

Wenn der Compiler einen Lambda-Ausdruck trifft, ist es zunächst absenkt (desugars) der Lambda-Körper in eine Methode, deren Argumente und die Art Spiel zurückzukehren dass der Lambda-Ausdruck

...

Methode Verweise auf die gleiche Weise wie Lambda-Ausdrücke behandelt werden, mit der Ausnahme, dass die meisten Verfahren Referenzen müssen nicht in ein neues Verfahren entzuckert werden; Wir können einfach eine Konstante für die referenzierte Methode laden und diese an die Metafactory übergeben.

Der einzige Unterschied zwischen den beiden stacktraces ist, dass die mit dem expliziten Lambda diese Zeile hinzugefügt:

at com.example.StackTractTest.lambda$0(StackTractTest.java:26) 

Es ist, weil das Lambda durch javac in eine neu generierte Methode übersetzt wurde, und Sie kann im Stacktrace tatsächlich sehen, dass diese neue Methode lambda$0 war.

Bei einer Methodenreferenz ist es nicht erforderlich, eine neue Methode zu generieren, da sie direkt auf eine vorhandene Methode verweist.

2

Nein - in der Tat erhalten Sie mehr Klarheit.

Die Tatsache, dass die at com.example.StackTractTest.lambda$0(StackTractTest.java:26) Linie in der Lambda-Version erscheint, wird man daran erinnert, dass ein Lambda für diese Technik geschaffen, während einer Methode Referenz verwendet schafft nicht nichts extra.

Das Lambda wird zur Laufzeit erstellt, die Methodenreferenz kann zur Kompilierzeit erstellt werden.

+2

Danke, aber ich bin mir nicht sicher, ich stimme zu, dass Sie mehr Klarheit bekommen.Während der Stack-Trace genau darstellt, was passiert, hat die Lambda-Version den praktischen Vorteil, den Verwendungsort zu identifizieren, an dem der Fehler aufgetreten ist. Diese Information scheint nicht für Methodenverweise verfügbar zu sein. Wenn ein Methodenverweis mehr als einmal in einer Pipeline aufgetreten ist, kann es hilfreich sein, zu wissen, welche Instanz eine Laufzeitausnahme ausgelöst hat. – henry

+2

Aber das ist nicht der Punkt, an dem der Fehler aufgetreten ist. Die Erstellungszeit ist nicht die gleiche wie die Nutzungsdauer für ein Lambda oder Method Handle. Stellen Sie sich vor, Sie würden einem Threadpool ein Lambda senden. Der Fehler tritt viel später auf, wenn die Methode, die das Lambda ausgibt, bereits beendet wurde. Sie fragen im Grunde nach Allocation-Site statt Call-Site, die Informationen Stack-Spuren enthalten traditionell nicht. Es wäre so, als würde man fragen: "Wo wurde das ausführbare Programm einem Threadpool zugewiesen?" – the8472