资讯专栏INFORMATION COLUMN

Java容器类研究1:Collection

AprilJ / 2470人阅读

摘要:集合类关系是和的父接口。相等必须是对称的,约定只能和其它相等,亦然。和接口在中引入,这个单词是和的合成,用来分割集合以给并行处理提供方便。这些并不立即执行,而是等到最后一个函数,统一执行。

集合类关系:

Collection   
├List   
│├LinkedList   
│├ArrayList   
│└Vector   
│ └Stack   
└Set   
Map  
├Hashtable  
├HashMap   
└WeakHashMap

Collection

java.util.Collection

Collection是List和Set的父接口。它继承了Iterable接口,所以每个Collection的子类应该是可以迭代访问其中的元素的。

我注意到一个有意思的函数,该函数在Java1.8中引入。该函数的功能是从集合中删除所有满足条件的元素,代码实现平平无奇,主要是函数有一个default修饰。Java8提供了default让接口中也可以实现方法体,目的是为了让开发者在给interface添加新方法时,不必再一一修改实现该接口的类,这些类可以使用默认的方法实现。

    default boolean removeIf(Predicate filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
Collection的equals

Collection的equals方法的重写需要小心谨慎。简单的使用引用比较还是比较简单安全的,值比较则会变复杂。相等必须是对称的,约定List只能和其它List相等,Set亦然。所以你自己实现的Collection类在和List、Set比较时应该返回false,因为即使你定制的Collection可以返回true,但是从List的视角来比较,返回的是false,不满足对称性。因此,也无法正确的实现一个既有List接口,又有Set接口的类。

遵照约定,如果你重写了equals方法,那么你要同时重写hashCode方法。c1.equals(c2)成立,则c1.hashCode()==c2.hashCode()。

Spliterator和Stream

Spliterator接口在Java8中引入,这个单词是Split和iterator的合成,用来分割集合以给并行处理提供方便。看个例子:

public class Ripper {
    public static void main(String[] args) {
        Collection numbers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }

        Spliterator sp = numbers.spliterator();
        System.out.println(sp.characteristics()); 
        System.out.println(sp.estimateSize());

        Spliterator sp2=sp.trySplit();
        System.out.println(sp.estimateSize());
        System.out.println(sp2.estimateSize());

        Spliterator sp3=sp.trySplit();
        System.out.println(sp.estimateSize());
        System.out.println(sp3.estimateSize());

        sp3.
    }
}

运行结果:

16464
10
5
5
3
2

相较于传统的iterator,spliterator可以递归的对集合进行划分,每个spliterator管理了原来集合中的部分元素。但是,每个spliterator并不是线程安全的,所以并行处理时,要保证每一个划分在同一个线程中进行处理。

Collection提供Stream对元素进行流处理,其中用到了spliterator。看个例子:

public class Ripper {
    public static void main(String[] args) {
        Collection numbers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }

        Stream stream = numbers.stream();
        List filterNum=stream.filter(item -> item > 5).collect(Collectors.toList());
        for(Integer i:filterNum){
            System.out.print(i+" ");
        }
        filterNum.set(0,100);
        System.out.println();
        for(Integer i:numbers){
            System.out.print(i+" ");
        }
    }
}

结果:

6 7 8 9 
0 1 2 3 4 5 6 7 8 9 

集合经过两步处理,过滤出了所有符合条件的元素。Stream整体处理过程分为两步:1.Configuration,2.Processing。Filter是Configuration,collect是Processing。还可以看出一点,最后获取的结果List是一个新建的List,并不和原List共享内存中的元素。

再看一个reduce的例子:

public class Ripper {
    public static void main(String[] args) {
        Collection numbers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }

        Stream stream = numbers.stream();
        int result=stream.reduce(0, (acc, item) -> acc + item);
        System.out.println(result);
    }
}

结果是:45。这是一个求和运算,其中第一个参数0是acc的初始值,acc表示上一步(acc, item) -> acc + item的结果,item是每次从stream中取的值。这些Configuration并不立即执行,而是等到最后一个Processing函数,统一执行。

在Collection中有parallelStream提供并行运算,并且使用了默认的spliterator对集合进行划分。例子如下:

public class Ripper {
    public static void main(String[] args) {
        Collection numbers = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            numbers.add(i);
        }

        Stream stream = numbers.parallelStream();
        stream.forEach(item -> System.out.print(item+" "));
        System.out.println();
        stream=numbers.stream();
        stream.forEach(item -> System.out.print(item+" "));
    }
}

结果:

1 2 6 8 0 4 3 5 9 7 
0 1 2 3 4 5 6 7 8 9 

可见,并行运算无法保证每个元素被处理的顺序。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67736.html

相关文章

  • Java 基础 | Collection 集合概览

    摘要:说到复盘基础,并不是所有的都会复盘,没那个时间更没那个必要。比如,一些基础的语法以及条件语句,极度简单。思前想后,我觉得整个计划应该从集合开始,而复盘的方式就是读源码。通常,队列不允许随机访问队列中的元素。 ​showImg(https://segmentfault.com/img/remote/1460000020029737?w=1080&h=711); 老读者都知道,我是自学转行...

    codergarden 评论0 收藏0
  • Java容器研究3:AbstractCollection

    摘要:随机访问数据是相对于顺序访问数据而言,例如链表的形式。方法将容器中的元素转化为数组的形式。在函数中,对容量每次扩展的大小,并且会检查是否会超过设定的最大数组长度。如果长度超过了限定值,则以原容量为底线,返回一个最大容量。 ArrayList继承自AbstractList,AbstractList为random access的数组提供了基本的实现。随机访问数据是相对于顺序访问数据而言,例...

    Donald 评论0 收藏0
  • 集合Collection总览

    前言 声明,本文使用的是JDK1.8 从今天开始正式去学习Java基础中最重要的东西--->集合 无论在开发中,在面试中这个知识点都是非常非常重要的,因此,我在此花费的时间也是很多,得参阅挺多的资料,下面未必就做到日更了... 当然了,如果讲得有错的地方还请大家多多包涵并不吝在评论去指正~ 一、集合(Collection)介绍 1.1为什么需要Collection Java是一门面向对象的语言,...

    FullStackDeveloper 评论0 收藏0
  • 通过面试题,让我们来了解Collection

    摘要:说一说迭代器通过集合对象获取其对应的对象判断是否存在下一个元素取出该元素并将迭代器对象指向下一个元素取出元素的方式迭代器。对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,也就是方法。 前言 欢迎关注微信公众号:Coder编程获取最新原创技术文章和相关免费学习资料,随时随地学习技术知识!** 本章主要介绍Collection集合相关知识,结合面试中会提到...

    HelKyle 评论0 收藏0
  • 容器Collection、Iterable、List、Vector(Stack)分析(三)

    摘要:容器相关的操作及其源码分析说明本文是基于分析的。通常,我们通过迭代器来遍历集合。是接口所特有的,在接口中,通过返回一个对象。为了偷懒啊,底层使用了迭代器。即返回的和原在元素上保持一致,但不可修改。 容器相关的操作及其源码分析 说明 1、本文是基于JDK 7 分析的。JDK 8 待我工作了得好好研究下。Lambda、Stream。 2、本文会贴出大量的官方注释文档,强迫自己学英语,篇幅...

    liaosilzu2007 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<