Являются ли трассировки стека менее ориентируемыми при использовании ссылок на методы по сравнению с лямбдами?
Я только что провел быстрый эксперимент в Eclipse.
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();
}
}
Когда проверка метода-ссылки не пройдена, начинается трассировка
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)
Нет ссылки на строку, на которой используется ссылка на метод, хотя конец трассы (не показан) действительно ссылается на строку с findFirst
на.
Пока начинается трассировка стека lamdba
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)
Что правильно идентифицирует лямбду, которая использовалась в строке 26.
Это особенность компилятора Eclipse или это общий недостаток использования ссылок на методы, которые следует учитывать при выборе между ними и лямбда-выражением?
2 ответа
Нет, это то, как это реализовано в настоящее время.
Цитирую статью Брайана Гетца о переводе лямбда-выражений:
Когда компилятор встречает лямбда-выражение, он сначала понижает (десугирует) лямбда-тело в метод, список аргументов и тип возвращаемого значения которого совпадают с лямбда-выражением
...
Ссылки на методы обрабатываются так же, как и лямбда-выражения, за исключением того, что большинство ссылок на методы не нужно вводить в новый метод; мы можем просто загрузить дескриптор постоянного метода для ссылочного метода и передать его метафории.
Единственное различие между вашими двумя стековыми трассами состоит в том, что в строке с явным лямбда добавлена следующая строка:
at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
Это потому, что лямбда была переведена javac
в недавно сгенерированный метод, и вы можете увидеть в трассировке стека, что этот новый метод был lambda$0
,
При наличии ссылки на метод нет необходимости создавать новый метод, поскольку он напрямую ссылается на существующий метод.
Нет - на самом деле вы получите больше ясности.
Тот факт, что at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
В лямбда-версии появляется строка, напоминающая о том, что для этого метода создана лямбда, в то время как использование ссылки на метод не создает ничего лишнего.
Лямбда создается во время выполнения, метод-ссылка может быть создана во время компиляции.