2015-11-13 11 views
8

Ho appena eseguito un rapido esperimento in Eclipse.Le tracce dello stack sono meno navigabili quando si utilizzano i riferimenti al metodo vs lambdas?

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

} 

Quando il saggio metodo di riferimento non riesce, la traccia inizia

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) 

Non v'è alcun riferimento di nuovo alla linea su cui viene utilizzato il metodo di riferimento anche se la fine della traccia (non mostrato) ricollega alla linea con findFirst su.

Mentre lo stacktrace Lamdba inizia

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) 

che identifica correttamente il lambda è stato utilizzato sulla linea 26.

Si tratta di una peculiarità del compilatore Eclipse o si tratta di uno svantaggio generale di utilizzare metodi riferimenti che dovrebbe essere considerato quando si sceglie tra loro e un lambda?

+2

No, questo come viene da Java. Lavorano per migliorare l'esperienza di stack-trace –

+1

Non ho mai sentito uno sviluppatore che chiedesse una traccia di stack più lunga prima ... – Holger

risposta

4

No, questo è il modo in cui è attualmente implementato.

quotatura a paper scritto da Brian Goetz circa la definizione di espressioni lambda:

Quando il compilatore rileva un'espressione lambda, esso primi abbassa (desugars) il corpo lambda in un metodo il cui elenco di argomenti e ritorno tipo di corrispondenza quello della espressione lambda

...

riferimenti metodo sono trattati allo stesso modo di espressioni lambda, se non che la maggior parte dei riferimenti metodo non devono essere private di zucchero in un nuovo metodo; possiamo semplicemente caricare un handle di metodo costante per il metodo di riferimento e passarlo al metafactory.

L'unica differenza tra le due stacktraces è che quello con il lambda esplicito ha questa linea ha aggiunto:

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

è perché il lambda è stato tradotto da javac in un metodo appena generato, e si può effettivamente vedere nello stacktrace che questo nuovo metodo era lambda$0.

Con un riferimento al metodo, non è necessario generare un nuovo metodo perché fa riferimento direttamente a un metodo esistente.

2

No - in effetti si ottiene una maggiore chiarezza.

Il fatto che la linea at com.example.StackTractTest.lambda$0(StackTractTest.java:26) appare nella versione lambda si sta ricordando che una lambda è creato per questa tecnica mentre si utilizza un metodo di riferimento non crea nulla in più.

Il lambda viene creato in fase di esecuzione, il metodo di riferimento può essere costruito in fase di compilazione.

+2

Grazie, ma non sono sicuro, sono d'accordo sul fatto che ottieni maggiore chiarezza.Mentre la traccia dello stack rappresenta esattamente ciò che sta accadendo, la versione lambda ha il vantaggio pratico di identificare il punto di utilizzo al quale si è verificato l'errore. Questa informazione non sembra essere disponibile per i riferimenti al metodo. Se un riferimento al metodo è apparso più di una volta in una pipeline, è utile sapere quale istanza ha attivato un'eccezione di runtime. – henry

+2

Ma non è questo il punto in cui si è verificato l'errore. Il tempo di creazione non è lo stesso del tempo di utilizzo di un handle di metodo o lambda. Immagina di inviare una lambda a un pool di thread. L'errore si verificherà molto più tardi quando il metodo di emissione del lambda è già uscito. Fondamentalmente stai chiedendo di allocation-site invece di call-site, le tracce dello stack di informazioni tradizionalmente non contengono. Sarebbe come chiedere "dove è stato assegnato il runnable a un threadpool". – the8472

Problemi correlati