【发布时间】:2018-02-13 21:10:30
【问题描述】:
给定一个带有两个 lambda 表达式的流:
Stream.of(new String[]{"a", "b"})
.map(s -> s.toUpperCase())
.filter(s -> s.equals("A"))
.count();
和一个匹配所有 lambdas 的 AspectJ 建议(取自 here)并打印出被调用方法的名称和 lamdba 的第一个参数的值:
@Before("execution(* *..*lambda*(..))")
public void beforeLambda(JoinPoint jp) {
System.out.println("lambda called: [" + jp.getSignature() + "] "+
"with parameter [" + jp.getArgs()[0] + "]");
}
输出是:
lambda called: [String aspectj.Starter.lambda$0(String)] with parameter [a]
lambda called: [boolean aspectj.Starter.lambda$1(String)] with parameter [A]
lambda called: [String aspectj.Starter.lambda$0(String)] with parameter [b]
lambda called: [boolean aspectj.Starter.lambda$1(String)] with parameter [B]
有没有办法在输出中不仅包含 lambda 的参数,还包含将 lambda 作为参数的 Stream 方法?换句话说:是否有可能在beforeLambda 方法中知道当前是否正在处理map 或filter 调用?
我正在寻找的输出是:
lambda called: [map] with parameter [a]
lambda called: [filter] with parameter [A]
lambda called: [map] with parameter [b]
lambda called: [filter] with parameter [B]
到目前为止我已经尝试过:
- 检查JoinPoint 中的信息。它包含由 lambda 表达式创建的方法的签名。实际方法的名称不同(
lambda$0用于映射,lambda$1用于过滤器),但由于它们是由编译器生成的,因此无法在代码中使用此信息。我可以尝试根据返回类型区分这两种情况,但在我的实际问题中,不同的 lambda 表达式也具有相同的返回类型。 - 尝试查找仅匹配其中一个调用的更具体的切入点表达式。同样,问题在于无法知道为映射或过滤器 lambda 生成的方法的名称。
- 在
beforeLambda运行时查看堆栈跟踪。在这两种情况下,堆栈跟踪中的最低条目是流的count方法,beforeLambda之前的最后一个条目是生成的方法:
at aspectj.Starter$LambdaAspect.beforeLambda(Starter.java:25)
at aspectj.Starter.lambda$0(Starter.java:14)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
[...more from java.util, but no hint to map or filter...]
at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
at aspectj.Starter.main(Starter.java:16)
- 在 Stream 的方法中添加第二个方面,打印出使用哪个参数调用哪个 Stream 方法(如果是
map和filter其中一个 lambda),以便我以后可以替换生成的方法输出中的名称。但是,Stream 方法中的 lambda 名称与beforeLambda输出中看到的方法名称不匹配:
@Before("call(* java.util.stream.Stream.*(..))")
public void beforeStream(JoinPoint jp) {
System.out.println("Stream method called: [" + jp.getSignature().getName() + "] with parameter [" + (jp.getArgs().length > 0 ? jp.getArgs()[0] : "null") + "])");
}
Stream method called: [of] with parameter [[Ljava.lang.String;@754c89eb])
Stream method called: [map] with parameter [aspectj.Starter$$Lambda$1/1112743104@512c45e7])
Stream method called: [filter] with parameter [aspectj.Starter$$Lambda$2/888074880@75e9a87])
Stream method called: [count] with parameter [null])
lambda called: [String aspectj.Starter.lambda$0(String)] with parameter [a]
lambda called: [boolean aspectj.Starter.lambda$1(String)] with parameter [A]
lambda called: [String aspectj.Starter.lambda$0(String)] with parameter [b]
lambda called: [boolean aspectj.Starter.lambda$1(String)] with parameter [B]
【问题讨论】: