• 设计模式


    迭代器模式:为集合提供一套统一的遍历方式,而不暴露集合内部的数据结构细节
    核心:实现Iterator{hasNext(),next()}接口,为集合数据遍历提供统一的方式

    public interface Iterator<E> {
        boolean hasNext();
        E next();
        default void remove() {throw new UnsupportedOperationException("remove");}
    }
    

    ArrayList 和 LinkedList遍历性能对比

    测试类型:for循环遍历,foreach遍历和iterator遍历 - foreach遍历底层实际是通过iterator接口完成的)

    结论:
    ① foreach遍历只是语法糖,底层实现是iterator,两者性能差不多
    ② ArrayList的遍历性能优于linkedList,(此处应该与内存结构有关)
    ArrayList遍历方式对性能影响不大(fori方式略优),LinkedList通过迭代器遍历性能比fori高得多

    • LinkedList.for循环遍历:get(index),每次循环需从头遍历找到对应的值,时间复杂度:0.5*n^2;
    • LinkedList.iterator遍历:维护了游标所指Element的引用,遍历时间复杂度:n
    > Mode=吞吐量 Score=平均执行次数
    > Benchmark                     Mode  Cnt      Score      Error   Units
    > ListTest.forAscArrayList     thrpt    5  40013.804 ±  236.174  ops/ms
    > ListTest.forDescArrayList    thrpt    5  39349.368 ± 5252.728  ops/ms
    > ListTest.foreachArrayList    thrpt    5  34618.842 ±  545.326  ops/ms
    > ListTest.iteratorArrayList   thrpt    5  34670.444 ±  301.078  ops/ms
    > ListTest.foreach8ArrayList   thrpt    5  33739.255 ± 2379.272  ops/ms
    
    > ListTest.forAscLinkedList    thrpt    5   3858.812 ±   43.145  ops/ms
    > ListTest.forDescLinkedList   thrpt    5   3885.409 ±   25.798  ops/ms
    > ListTest.foreachLinkedList   thrpt    5  17039.682 ±   52.282  ops/ms
    > ListTest.iteratorLinkedList  thrpt    5  17553.558 ±   40.178  ops/ms
    > ListTest.foreach8LinkedList  thrpt    5  17178.035 ± 3644.734  ops/ms
    
    @BenchmarkMode(Mode.Throughput)                                      // 测试类型:吞吐量
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)       // 预热 5 轮,每次 1s
    @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)  // 测试 5 轮,每次 2s
    @Fork(1)               // fork 1 个线程
    @State(Scope.Thread)   // 每个测试线程一个实例
    public class ListTest {
        private static List<String> list = null;
        static {
            list = new LinkedList(128);
            for(int i = 0;i < 50;i++){
                list.add(UUID.randomUUID().toString());
            }
        }
    
        // 1. foreach遍历
        @Benchmark
        public static void foreachList(){
            for (String j : list) {
            }
        }
    
        // 2. iterator遍历
        @Benchmark
        public static void iteratorList(){
            String j;
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()){
                j = iterator.next();
            }
        }
    
        // 3. for 递减遍历
        @Benchmark
        public static void forDescList(){
            String j;
            for(int i = list.size() - 1;i >= 0; i--){
                j = list.get(i);
            }
        }
    
        // 4. for 递增遍历
        @Benchmark
        public static void forAscList(){
            String j;
            int size = list.size();
            for(int i = 0;i < size; i++){
                j = list.get(i);
            }
        }
    
        // 5. java8 新增foreach
        @Benchmark
        public static void foreachJava8(){
            list.forEach(item -> {
                
            });
        }
    }
    

    HashMap遍历方式性能对比

    1:foreach遍历只是语法糖,底层实现是iterator,两者性能差不多
    2:KeySet遍历性能明显低于EntrySet,原因:keySet多有一步map.get(key)操作
    3:JDK8 Stream性能需根据具体场景考虑,Stream优点:为集合的遍历和处理提供了新的方法

    Benchmark                  Mode  Cnt      Score     Error   Units
    MapTest.foreachKeySet     thrpt   25  11189.487 ± 164.446  ops/ms
    MapTest.iteratorKeySet    thrpt   25  11286.328 ± 223.540  ops/ms
    MapTest.foreachEntrySet   thrpt   25  17457.300 ± 434.603  ops/ms
    MapTest.iteratorEntrySet  thrpt   25  17159.188 ± 961.122  ops/ms
    MapTest.foreachjava8      thrpt   25  18068.674 ±  92.609  ops/ms
    MapTest.parallelStream    thrpt   25     76.718 ±   5.382  ops/ms
    MapTest.stream            thrpt   25   7361.508 ± 119.650  ops/ms
    
    @BenchmarkMode(Mode.Throughput) // 测试类型:吞吐量
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) // 预热 5 轮,每次 1s
    @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 2s
    //@Fork(1) // fork 1 个线程
    @State(Scope.Thread) // 每个测试线程一个实例
    public class MapTest {
        private static HashMap<String,Object> map = null;
        static {
            map = new HashMap<>(128);
            for(int i = 0;i < 10;i++){
                map.put(UUID.randomUUID().toString(),UUID.randomUUID());
            }
        }
    
    
        // 1. foreach entrySet遍历
        @Benchmark
        public static void foreachEntrySet(){
            // 1. EntrySet - foreach
            String key;
            Object value;
            for (Map.Entry<String, Object> entry : map.entrySet()){
                key = entry.getKey();
                value = entry.getValue();
            }
        }
    
        // 2. iterator entrySet遍历
        @Benchmark
        public static void iteratorEntrySet(){
            String key;
            Object value;
            Map.Entry<String,Object> entry;
            Iterator<Map.Entry<String,Object>> entrySetIterator = map.entrySet().iterator();
            while (entrySetIterator.hasNext()){
                entry = entrySetIterator.next();
                key = entry.getKey();
                value = entry.getValue();
            }
        }
    
        // 3. foreach keySet遍历
        @Benchmark
        public static void foreachKeySet(){
            // 1. EntrySet - foreach
            Object value;
            for (String key : map.keySet()){
                value = map.get(key);
            }
        }
    
        // 4. iterator keySet遍历
        @Benchmark
        public static void iteratorKeySet(){
            String key;
            Object value;
            Iterator<String> keySetIterator =  map.keySet().iterator();
            while (keySetIterator.hasNext()){
                key = keySetIterator.next();
                value = map.get(key);
            }
        }
    
        // 5. lambda遍历
        @Benchmark
        public static void lambda(){
            map.forEach((key,value) -> {
            });
        }
    
        // 6. stream串行遍历
        @Benchmark
        public static void stream(){
            map.entrySet().stream().forEach((entry) -> {
                entry.getKey();
                entry.getValue();
            });
        }
    
        // 7. stream并行遍历
        @Benchmark
        public static void parallelStream(){
            map.entrySet().parallelStream().forEach((entry) -> {
                entry.getKey();
                entry.getValue();
            });
        }
    }
    

    Stream API

    Java8新特性:为集合的遍历和处理提供了新的方法
    Stream API主要是解决数据处理和运算问题

    特点:

    • 将一系列操作构成一个管道,并且可以在管道的节点上进行处理(Element拷贝推入流中,执行中间处理,完成终止操作)
    • Stream 自己不会存储元素,也不会改变源对象

    总结:Stream()在遍历上性能低于常规遍历方式,但其灵活性和代码简洁性完全优于常规遍历(并行流性能需根据实际业务情况判断)


    欢迎疑问、期待评论、感谢指点 -- kiqi,愿同您为友

    -- 星河有灿灿,愿与之辉

  • 相关阅读:
    将博客搬至CSDN
    神州笔记本电脑【K670D】安装 Ubuntu18.04 系列操作
    ValueError: Unknown label type: 'continuous'
    Spark: JAVA_HOME is not set
    IDEA 搭建 Spark 源码 (Ubuntu)
    XX-Net 解决IPV6 不稳定,时好时坏。
    解决SBT下载慢,dump project structure from sbt?
    pip install kaggle 出现 【网络不可达】?
    Git clone 克隆Github上的仓库,速度慢?
    进程间的通信方式
  • 原文地址:https://www.cnblogs.com/kiqi/p/14058657.html
Copyright © 2020-2023  润新知