Являются ли трассировки стека менее ориентируемыми при использовании ссылок на методы по сравнению с лямбдами?

Я только что провел быстрый эксперимент в 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) В лямбда-версии появляется строка, напоминающая о том, что для этого метода создана лямбда, в то время как использование ссылки на метод не создает ничего лишнего.

Лямбда создается во время выполнения, метод-ссылка может быть создана во время компиляции.

Другие вопросы по тегам