Давайте посмотрим на байт-код.
object ExtraClosure {
val fail = (x: Any) => { throw new RuntimeException }
List(1).foreach(fail)
}
Находим внутри (единственной) анонимной функции:
public final scala.runtime.Nothing$ apply(java.lang.Object);
Code:
0: new #15; //class java/lang/RuntimeException
3: dup
4: invokespecial #19; //Method java/lang/RuntimeException."<init>":()V
7: athrow
public final java.lang.Object apply(java.lang.Object);
Code:
0: aload_0
1: aload_1
2: invokevirtual #27; //Method apply:(Ljava/lang/Object;)Lscala/runtime/Nothing$;
5: athrow
Так что на самом деле это не лишнее закрытие. У нас есть один метод, перегруженный двумя различными возвращаемыми значениями (что совершенно нормально для JVM, поскольку он обрабатывает тип всех параметров как часть сигнатуры функции). Функция является универсальной, поэтому она должна возвращать объект, но код, который вы написали, возвращает конкретно Nothing
, она также создает метод, который возвращает ожидаемый тип.
Есть разные способы обойти это, но ни один не обходится без их недостатков. Однако это тот тип вещей, в котором JVM довольно хорошо справляются со своими обязанностями, поэтому я не стал бы слишком беспокоиться об этом.
Редактировать: И, конечно, во втором примере вы использовали def
, а anonfun
- это класс, который оборачивает этот def
в функциональный объект. Это, конечно, необходимо, поскольку foreach
занимает Function1
. Вы должны как-то сгенерировать это Function1
.