当finalizeOperation正在运行时(在更大的应用程序中生产):
11 at com.company.SomeClass.lambda$finalizeOperation$0 (SomeClass.java:51)
12 at com.company.SomeClass$$Lambda$135/2085968933.accept (Unknown source)
13 at java.util.ArrayList.forEach (ArrayList.java:1249)
14 at com.company.SomeClass.finalizeOperation (SomeClass.java:51)
构建了以下调用树/堆栈跟踪:
public class Test {
public static void main(String... args) {
List<String> names = Arrays.asList("adam", "");
Stream lengths = names.stream().map(name -> check(name));
lengths.count();
}
public static int check(String s) {
if (s.equals(""))
throw new IllegalArgumentException();
return s.length();
}
}
我对第12行感兴趣 - 这个名字来自哪里?为什么我会期望一个类的名字随机数?
编辑: 以下是来自blog post mentioned by Niklas P的代码:
Exception in thread "main" java.lang.IllegalArgumentException
at Test.check(Test.java:19)
at Test.lambda$main$0(Test.java:12)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at Test.main(Test.java:14)
但结果不包含此数字名称,堆栈跟踪是(jdk8u102):
Exception in thread "main" java.lang.IllegalArgumentException
at Test.check(Test.java:18)
at Test.lambda$main$0(Test.java:11)
at Test$$Lambda$1/1554547125.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at Test.main(Test.java:13)
在jdk8u25上有数字:
$img = "img"; // input name="img"
$this->upload->do_upload($img);
答案 0 :(得分:5)
这里有两个重叠的问题。首先,当您将lambda表达式转换为对象类型时,必须有一些实现功能接口的东西 - 细节不是那么重要;唯一需要了解的是,有一些实现接口并调用lambda表达式的代码或方法引用的目标。
当前的JRE实现生成匿名类,顾名思义,它们不依赖于它们的名称是唯一的。类名后面打印的数字是此属性的工件。无论哪种方式,无论是否有数字,您都无法使用@ContextConfiguration(classes = {WebConfig.class})
来查找这些类。
在堆栈跟踪中使用合成工件对Java来说并不是什么新鲜事。使用内部类时会生成存取方法,例如
ClassLoader
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
public class Test {
public static void main(String... args) {
List<String> names = Arrays.asList("adam", "");
Stream lengths = names.stream().map(new Function<String, Integer>() {
public Integer apply(String name) {
return check(name);
}
});
lengths.count();
}
private static int check(String s) {
if (s.equals(""))
throw new IllegalArgumentException();
return s.length();
}
}
注意堆栈跟踪中是否存在Exception in thread "main" java.lang.IllegalArgumentException
at Test.check(Test.java:17)
at Test.access$000(Test.java:5)
at Test$1.apply(Test.java:10)
at Test$1.apply(Test.java:8)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
… (shortened it a bit)
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at Test.main(Test.java:13)
,它不会出现在源代码中;它的关联行号是没有意义的,它只是外部类定义的开始。
现在,似乎堆栈跟踪生成发生了变化,在最近的JRE版本中省略了匿名类的合成成员。这也将影响反射调用的堆栈轨迹,例如,使用access$000
个实例。这可能被认为对大多数用例有用,但它也暗示在某些情况下调用者和被调用者之间可能存在不匹配,因为堆栈跟踪报告调用者调用接口方法,但最终在其他地方,例如
MethodHandle
将打印
import java.util.*;
import java.util.stream.Stream;
public class Test {
public static void main(String... args) {
Stream.of("adam", "", null).filter("foo"::contains).count();
}
}
其中Exception in thread "main" java.lang.NullPointerException
at java.lang.String.contains(String.java:2133)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
…
包含ReferencePipeline.java:174
接口的accept
方法的调用,但最终在类Predicate
的方法contains
中。我们可以最大限度地解决这个问题:
String
将在最新的JRE上生成以下内容:
import java.util.*;
import java.util.stream.Stream;
public class Test {
public static void main(String... args) {
Stream.of("adam", "", null).filter(String::isEmpty).count();
}
}
省略最终将在Exception in thread "main" java.lang.NullPointerException
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at Test.main(Test.java:6)
实例上调用isEmpty
的合成代码,由于String
仅包含ReferencePipeline.java:174
方法的调用,因此更加令人困惑。 interface
实例不是interface
(在该代码中已经检查过很久)。
请注意,这是一项动态发展。使用Java 9,将有StackWalker
API,允许应用程序使用已配置的隐藏/反射堆栈帧处理生成自己的快照。一旦应用程序使用此API创建可预测的堆栈跟踪,即不再依赖null
的特定行为,throwable的行为可以通过JVM选项或系统属性进行配置......
答案 1 :(得分:1)
这些数字来自匿名类,为lambda操作创建的JVM - 请参见:the-dark-side-of-lambda-expressions-in-java-8