欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

原文链接: dzone 翻译: ImportNew.com - yizhe 译文链接 次  来源:昆山软开发 时间:2018-08-11

本文由 ImportNew - yizhe 翻译自 dzone。接待插手翻译小组。转载请见文末要求。

通过本文,你可以更深入的进修 Java 语言中 forEach 语法的常识,以及它和 C 语言形式的 for 轮回、 Steam API 的比拟。

简介

Java 措施员常常利用容器,好比 ArrayList 和 HashSet。Java 8 中的 lambda 语法和 steaming API 可以让我们更利便的利用容器。大部门环境下,我们仅仅处理惩罚几千个元素,也不会去思量机能问题。可是,劳务派遣管理系统昆山软件开发,在一些极度场景下,假如我们需要遍历上百万个元素,机能问题就凸显出来了。

本文将回收 JMH 计较每块代码的运行时间。

forEach vs. C Style vs. Stream API

遍历是一个根基的成果。所有编程语言都提供了简朴的语法,让措施员去遍历容器。Steam API 以一种很是直接的形式来遍历容器。

    public List<Integer> streamSingleThread(BenchMarkState state){
        List<Integer> result = new ArrayList<>(state.testData.size());
        state.testData.stream().forEach(item -> {
            result.add(item);
        });
        return result;
    }
    public List<Integer> streamMultiThread(BenchMarkState state){
        List<Integer> result = new ArrayList<>(state.testData.size());
        state.testData.stream().parallel().forEach(item -> {
            result.add(item);
        });
        return result;
    }

forEach 轮回也很简朴:

    public List<Integer> forEach(BenchMarkState state){
      List<Integer> result = new ArrayList<>(state.testData.size());
      for(Integer item : state.testData){
        result.add(item);
      }
      return result;
    }

C 语言形式的 for 轮回烦琐一些,不外依然很紧凑:

    public List<Integer> forCStyle(BenchMarkState state){
      int size = state.testData.size();
      List<Integer> result = new ArrayList<>(size);
      for(int j = 0; j < size; j ++){
        result.add(state.testData.get(j));
      }
      return result;
    }

以下是机能陈诉:

Benchmark                               Mode  Cnt   Score   Error  Units
TestLoopPerformance.forCStyle           avgt  200  18.068 ± 0.074  ms/op
TestLoopPerformance.forEach             avgt  200  30.566 ± 0.165  ms/op
TestLoopPerformance.streamMultiThread   avgt  200  79.433 ± 0.747  ms/op
TestLoopPerformance.streamSingleThread  avgt  200  37.779 ± 0.485  ms/op

利用 C 语言形式的 for 轮回,JVM 每次仅仅增加一个数字,然后直接从内存里读出数据。这使得它很是迅速。可是 forEach 就大纷歧样,按照 StackOverFlow 的这篇答复,和 Oracle 的文章,JVM 需要把 forEach 转换成一个 iterator,劳务派遣管理系统,然后每个元素都挪用一次 hasNext() 要领。这就是 forEach 比 C 语言的形式慢一些的原因。

哪一个是遍历 Set 最高效的要领呢?

我们先界说测试数据集:

    @State(Scope.Benchmark)
    public static class BenchMarkState {
        @Setup(Level.Trial)
        public void doSetup() {
            for(int i = 0; i < 500000; i++){
                testData.add(Integer.valueOf(i));
            }
        }
        @TearDown(Level.Trial)
        public void doTearDown() {
            testData = new HashSet<>(500000);
        }
        public Set<Integer> testData = new HashSet<>(500000);
    }

Java 中的 Set 也支持 Steam API 和 forEach 轮回。参考之前的测试,假如我们把 Set 转换成 ArrayList,然后遍历 ArrayList,或者机能会好一些?

    public List<Integer> forCStyle(BenchMarkState state){
        int size = state.testData.size();
        List<Integer> result = new ArrayList<>(size);
        Integer[] temp = (Integer[]) state.testData.toArray(new Integer[size]);
        for(int j = 0; j < size; j ++){
            result.add(temp[j]);
        }
        return result;
    }

假如把 iterator 和 C 语言形式团结起来呢?

    public List<Integer> forCStyleWithIteration(BenchMarkState state){
        int size = state.testData.size();
        List<Integer> result = new ArrayList<>(size);
        Iterator<Integer> iteration = state.testData.iterator();
            for(int j = 0; j < size; j ++){
            	result.add(iteration.next());
            }
        return result;
    }

可能,简朴的遍历怎么样?

    public List<Integer> forEach(BenchMarkState state){
        List<Integer> result = new ArrayList<>(state.testData.size());
        for(Integer item : state.testData) {
            result.add(item);
        }
        return result;
    }