命名(toString)用于调试目的的Lambda表达式 [英] Naming(toString) Lambda-Expressions for Debugging purpose

查看:169
本文介绍了命名(toString)用于调试目的的Lambda表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有时候,命名lambdas是有用的。特别是当你把它们作为参数传递。



一个简单的例子是

  public class Main {
public static void main(String [] args){
谓词< String> p = nameIt(isNotEmpty,(s) - >!s.trim()。isEmpty());
maybePrint(Hello,p);
maybePrint(,p);
}

static< T> void maybePrint(T s,Predicate< T> pred){
if(pred.test(s)){
System.out.println(s.toString());
} else {
System.err.println(pred +say no to \+ s +\);
}
}
}

某些功能由jvm命名为lambdas,而不会失去幕后的伟大的性能优化。



这样的事情对我来说会很好:

 谓词< String> p = nameIt(isNotEmpty,(s) - >!s.trim()。isEmpty()); 


解决方案

这是我的解决方案(灵感来自于andersschuller的解决方案 http://stackoverflow.com/a/23705160/1325574 )。可能有一些角色(Classloading),这个实现不起作用,但是对于最简单的例子,它可以工作。



我已经用我的有限jmh知识:
https://gist.github.com/picpromusic/4b19c718bec5a652731a65c7720ac5f8



命名结果是为了执行@stuartmarks 命名(toString)Lambda表达式用于调试目的

 #运行完成。总时间:00:40:31 

基准模式Cnt分数错误单位
MyBenchmark.testNamedPredicate thrpt 200 45938970,625±615390,483 ops / s
MyBenchmark.testPredicate thrpt 200 23062083,641±154933,675 ops / s
MyBenchmark.testPredicateReal thrpt 200 48308347,165±395810,356 ops / s
MyBenchmark.testToString thrpt 200 138366708,182±1177786,195 ops / s
MyBenchmark.testToStringNamed thrpt 200 252872229,907±8044289,516 ops / s
MyBenchmark.testToStringReal thrpt 200 6670148,202±40200,984 ops / s

您可以看到它比使用未命名的lambda大约慢2倍。所以在设置-DnamedLambdasEnabled = true时要小心。对我来说,在Real-lambda上调用toString是非常昂贵的。也许有人可以解释一下,或者我的jmh测试是愚蠢的。



这里是代码:

  / ** 
* Helper类为调试目的而赋予lambda一个名称(toString)
*
* /
public class LambdaNamer {

私有静态方法TO_STRING;

static {
try {
TO_STRING = Object.class.getMethod(toString);
} catch(NoSuchMethodException | SecurityException e){
抛出新的RuntimeException(Denmark的状态有一些东西!);
}
}

/ **
*覆盖给定lambda的toStringMethod。
*
* @param名称toString结果的lambda
* @param obj要封装的lambda
* @return命名的lambda
* /
public静态< T> T nameIt(String name,T obj){
if(Boolean.getBoolean(namedLambdasEnabled)){
Class< T> clazz =(Class< T>)obj.getClass();
类<?> [] interfaces = clazz.getInterfaces();

return(T)Proxy.newProxyInstance(//
obj.getClass()。getClassLoader(),//
interfaces,//
(Object proxy,方法方法,Object [] args) - > {
if(TO_STRING.equals(method)){
return name;
} else {
return method.invoke ,args);
}
});
} else {
return obj;
}
}
}

你有其他解决方案吗?可能是没有性能影响的东西?


Sometimes it is usefull to name lambdas. Especially when you pass them around as parameter.

A realy simple example is

public class Main {
    public static void main(String[] args) {
        Predicate<String> p = nameIt("isNotEmpty", (s) ->  !s.trim().isEmpty());
        maybePrint("Hello", p);
        maybePrint("    ", p);
    }

    static <T> void maybePrint(T s, Predicate<T> pred) {
        if (pred.test(s)) {
            System.out.println(s.toString());
        } else {
            System.err.println(pred + " says no to \"" + s + "\"");
        }
    }
}

It would be nice to have some functionality by the jvm to name lambdas without loosing the great performance optimizations behind the scenes.

Somethink like this would be fine for me:

Predicate<String> p = nameIt("isNotEmpty", (s) -> !s.trim().isEmpty());

解决方案

This is my solution(inspired from the solution of andersschuller at http://stackoverflow.com/a/23705160/1325574) for the problem. There maybe some corner cases(Classloading) where this implementation does not work, but for the most simple cases it works.

I have created a small performance test of this with my limited jmh knowledge: https://gist.github.com/picpromusic/4b19c718bec5a652731a65c7720ac5f8

The "Named"-results are measured for the implementation of the answer of @stuartmarks Naming(toString) Lambda-Expressions for Debugging purpose

# Run complete. Total time: 00:40:31

Benchmark                        Mode  Cnt          Score         Error  Units
MyBenchmark.testNamedPredicate  thrpt  200   45938970,625 ±  615390,483  ops/s
MyBenchmark.testPredicate       thrpt  200   23062083,641 ±  154933,675  ops/s
MyBenchmark.testPredicateReal   thrpt  200   48308347,165 ±  395810,356  ops/s
MyBenchmark.testToString        thrpt  200  138366708,182 ± 1177786,195  ops/s
MyBenchmark.testToStringNamed   thrpt  200  252872229,907 ± 8044289,516  ops/s
MyBenchmark.testToStringReal    thrpt  200    6670148,202 ±   40200,984  ops/s

As you can see it is roughly 2 times slower than using an unnamed lambda. So be carefull in setting -DnamedLambdasEnabled=true. Interessting for me is that it is surprisingly expensive to call toString on an Real-lambda. Maybe someone can explain that, or my jmh-test is stupid.

Here is the code:

/**
 * Helper Class to give lambda a name ("toString") for debugging purpose
 *
 */
public class LambdaNamer {

    private static Method TO_STRING;

    static {
        try {
            TO_STRING = Object.class.getMethod("toString");
        } catch (NoSuchMethodException | SecurityException e) {
            throw new RuntimeException("There is something rotten in state of denmark!");
        }
    }

    /**
     * Overrides toString "Method" for a given lambda.
     * 
     * @param name toString result of lambda
     * @param obj the lambda to encapsulate
     * @return the named lambda
     */
    public static <T> T nameIt(String name, T obj) {
        if (Boolean.getBoolean("namedLambdasEnabled")) {
            Class<T> clazz = (Class<T>) obj.getClass();
            Class<?>[] interfaces = clazz.getInterfaces();

            return (T) Proxy.newProxyInstance(//
                    obj.getClass().getClassLoader(),//
                    interfaces, //
                    (Object proxy, Method method, Object[] args) -> {
                        if (TO_STRING.equals(method)) {
                            return name;
                        } else {
                            return method.invoke(obj, args);
                        }
                    });
        } else {
            return obj;
        }
    }
}

Do you have other solutions? Maybe something that does not have performance implications?

这篇关于命名(toString)用于调试目的的Lambda表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆