Naming(toString) Lambda-Expressions for Debugging purpose

前端 未结 2 717
情歌与酒
情歌与酒 2020-12-22 06:09

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

A realy simple example is

public class Main {
    publi         


        
相关标签:
2条回答
  • 2020-12-22 06:14

    This is my solution(inspired from the solution of andersschuller at https://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?

    0 讨论(0)
  • 2020-12-22 06:37

    Here's an alternative that comes to mind:

    static <T> Predicate<T> nameIt(String name, Predicate<? super T> pred) {
        return new Predicate<T>() {
            public String toString() { return name; }
            public boolean test(T t) { return pred.test(t); }
        };
    }
    

    This seems pretty simple. Although I haven't benchmarked it, it seems like it ought to be pretty fast. It adds a single object and one method call, and it avoids boxing/unboxing overhead.

    The drawback is that you have to write a little function like this for every functional interface for which you want to provide named instances.

    0 讨论(0)
提交回复
热议问题