使用 java.util.function中的方法实现代码 比正常使用java代码慢了十倍?

发布于 2022-09-11 17:01:33 字数 4067 浏览 21 评论 0

问题描述

今天学习了一下java.util.function中的几个方法,觉得很帅很优雅,于是学的过程中照搬着把我以前的

一个判断字段是否为空的代码重写了一遍(有些业务定义如果某个字段等于-1也默认认为它为空).

实现之后对照着跑了一遍,发现性能居然比原来的代码慢了十倍,所以有些疑惑,先看看代码吧:

相关代码

// 旧代码

public static <T> boolean isBlank(T t) {

    if (t == null) {
        return true;
    }

    if (t instanceof List) {
        if (((List) t).size() == 0) {
            return true;
        }
    } else if (t instanceof Map) {
        if (((Map) t).size() == 0) {
            return true;
        }
        if (((Map) t).get("-1") != null && ((Map) t).get("-1").equals("-1")) {
            return true;
        }
    } else if (t instanceof Set) {
        if (((Set) t).size() == 0) {
            return true;
        }
    } else if (t instanceof Object[]) {
        if (((Object[]) t).length == 0) {
            return true;
        }
    } else if (t instanceof String) {
        String str = (String) t;
        if (str.length() == 0)
            return true;

        str = str.trim();
        if (str.length() == 0)
            return true;
    }
    return false;
}

public static <T> boolean isinFallback(T t) {
    Class<?> c = t.getClass();
    Method[] methods = c.getMethods();
    try {
        for (Method method : methods) {
            if (method.getName().equals("getId")) {
                Object o = method.invoke(t);
                if (o == null) {
                    return true;
                }
                if (o.equals(-1L)) {
                    return true;
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        return true;
    }
    return false;
}

//新代码

private static final Function<Method[], Method> filter = (s) -> {
    for (Method m : s) {
        if (m.getName().equals("getId")) {
            return m;
        } else if (m.getName().equals("getUid")) {
            return m;
        }
    }
    return null;
};

private static final Predicate<Object> object = (s) -> s.equals("-1");

private static final Function<Object, Predicate> getPre = (s) -> {
    if (s instanceof List) {
        return (Predicate<List>) l -> l.size() == 0;
    } else if (s instanceof Map) {
        return (Predicate<Map>) l -> l.size() == 0 || l.get("-1") != null;
    } else if (s instanceof Set) {
        return (Predicate<Set>) l -> l.size() == 0;
    } else if (s instanceof Object[]) {
        return (Predicate<Object[]>) l -> Objects.nonNull(l) && l.length == 0;
    } else if (s instanceof String) {
        return (Predicate<String>) String::isEmpty;
    }
    return null;
};


public static <T> boolean isBlank(T t) {
    if (t == null) {
        return true;
    }
    if (t instanceof String) {
        String str = (String) t;
        str = str.trim();
        return getPre.apply(str).test(str);
    }
    Predicate apply = getPre.apply(t);
    return apply != null && apply.test(t);
}

public static <T> boolean isinFallback(T t) {
    Class<?> c = t.getClass();
    Method[] method = c.getMethods();
    try {
        Method apply = filter.apply(method);
        return apply != null && object.or(oj -> oj.equals(-1L)).test(apply.invoke(t));
    } catch (IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }
    return false;
}

测试代码:

clipboard.png

测试结果:

clipboard.png

问题:

有三个方法结果不一致是因为我加了一些新的判断,所以不用在意,疑惑的地方是代码逻辑完全没有变,仅仅是把实现方法换成了java8的新实现方式,结果性能居然差了这么多.所以问题是:

1.如果是我代码写的逻辑不对导致的这个问题,那我是错在那些地方呢?

2.看方法介绍,Predicate这个类之所以存在似乎就是因为它能做一些判断性的动作,可是性能这么慢又有什么用它的必要呢?

3.如果是我杀鸡用牛刀了那么java.util.function包下的几个工具类的正确使用场景是在什么地方呢(Predicate, Consumer, Function, Supplier, UnaryOperator, BinaryOperator)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

咋地 2022-09-18 17:01:33

我不知道你知不知道这个属于Java反射的内容?
反射因为是涉及到动态类型解析的,所以他用不上虚拟机的优化,反射操作的性能是低于非反射操作的

酒废 2022-09-18 17:01:33

代码貌似没贴全,不知道是不是这样的问题:

  1. 直接判断 vs 包了一层的判断,后者肯定是慢的
  2. 但是如果有jit,把后者内联掉了,性能差距应该就不大了
  3. java8的函数接口更多是为了写lambda用的,不是直接拿出来用的
你在看孤独的风景 2022-09-18 17:01:33

这个问题我也注意到了,但不是楼主说的那样使用 java.util.function中的方法实现代码 比正常使用java代码慢了十倍?。他是在初始化的时候慢。楼主用的测试用例,我稍微修改了一下就能看出。(这里的LegalPredicate.isBlank()方法都是用的Function实现的)

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    Object o1 = null;
    System.out.println("o1====>" + LegalPredicate.isBlank(o1));
    Object o2 = "";
    System.out.println("o2====>" + LegalPredicate.isBlank(o2));
    long endTime = System.currentTimeMillis();
    System.out.println("程序运行时间: " + (endTime - startTime) + "ms");

    startTime = System.currentTimeMillis();
    Object o3 = null;
    System.out.println("o3====>" + LegalPredicate.isBlank(o3));
    Object o4 = "";
    System.out.println("o4====>" + LegalPredicate.isBlank(o4));
    endTime = System.currentTimeMillis();
    System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
}

clipboard.png
看到没,第一个程序运行时间远超第二个(第二个由于太快了,运行时间显示为0)。
或许有的人会说,说不定程序缓存了第一次的结果,所以第二次没有判断直接用的缓存结果所以快了。那么再把测试用例改一下:

public static void main(String[] args) {
    long startTime = System.currentTimeMillis();
    Object o1 = null;
    System.out.println("o1====>" + LegalPredicate.isBlank(o1));
    long endTime = System.currentTimeMillis();
    System.out.println("程序运行时间: " + (endTime - startTime) + "ms");

    startTime = System.currentTimeMillis();
    Object o3 = null;
    System.out.println("o3====>" + LegalPredicate.isBlank(o3));
    endTime = System.currentTimeMillis();
    System.out.println("程序运行时间: " + (endTime - startTime) + "ms");
}

clipboard.png
这时在同一台电脑上(性能一样),减少了一个运算对象,程序时间和刚才差不多,如果是运算慢,那这时候运算时间应该是刚才的一半左右。

所以不是使用java.util.function中的方法实现代码 比正常使用java代码慢了十倍?,只是加载function方法时间慢。同样的我发现加载lambda表达式的也会慢

不过具体原因我也不知道,这应该是JVM的一些问题吧,对一块研究的还不深,网上也没找到资料,希望如果有人知道可以给出答案,或者探讨一下。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文