文档开发者中心
我的

跟我一起复习Java(2)

1 集合体系

集合是存储多个元素的容器,数组长度固定,不能满足长度变化的需求。其特点:

  • 长度可变

  • 存储元素可以是引用类型

  • 可以存储多种类型的对象

1.1 Iterator

Iterator接口:

  • 对 Collection 进行迭代的迭代器,即对所有的Collection容器进行元素取出的公共接口。

  • 提供boolean hasNext()和E next()两个方法

ListIterator:

  • 只能用于List的迭代器。

  • 在使用迭代器迭代的过程中需要使用集合中的方法操作元素,出现ConcurrentModificationException异常时,可以使用ListIterator避免

1.2 Collection

Collection接口:

  • List接口:有序(存入和取出的顺序一致),元素都有索引(下标),元素可以重复。

    • Vector:内部是 数组 数据结构,是同步的。增删,查询都很慢!100%延长(几乎不用了)

    • ArrayList:内部是 数组 数据结构,是不同步的。替代了Vector,查询的速度快,增删速度慢。50%延长。查询时是从容器的第一个元素往后找,由于数组的内存空间是连续的,所以查询快;增删的话所有元素内存地址都要改变,所以增删慢。

    • LinkedList:内部是 链表 数据结构,是不同步的。增删元素的速度很快。同理,链表的内存空间是不连续的,所以查询慢;增删时只需改变单个指针的指向,所以快。

  • Set接口:无序,元素不能重复。Set接口中的方法和Collection一致。

    • HashSet:内部数据结构是哈希表 ,是不同步的。

    • LinkedHashSet:内部数据结构是哈希表和链表,是有顺序的HashSet。

    • TreeSet:内部数据结构是有序的二叉树,它的作用是提供有序的Set集合,是不同步的。

List接口:

  • 有一个最大的共性特点就是都可以操作角标,所以LinkedList也是有索引的。list集合可以完成对元素的增删改查。

Set和List的区别:

  • Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。

  • Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 。

  • List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变。

1.3 Map

Map接口:

  • 一次添加一对元素,Collection 一次添加一个元素。

  • Map也称为双列集合,Collection集合也称为单列集合。

  • map集合中存储的就是键值对,map集合中必须保证键的唯一性

Map常用的子类:

  • Hashtable :内部结构是哈希表,是同步的。不允许null作为键,null作为值。

    • Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。

  • HashMap : 内部结构是哈希表,不是同步的。允许null作为键,null作为值。

  • TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。

Map的迭代方法(Map本身没有迭代器):

  • 利用Map接口的values()方法,返回此映射中包含的值的 Collection(值不唯一),然后通过Collecion的迭代器进行迭代。(只需要Value,不需要Key的时候)

  • 通过keySet方法获取map中所有的键所在的Set集合(Key和Set的都具有唯一性),再通过Set的迭代器获取到每一个键,再对每一个键通过Map集合的get方法获取其对应的值即可。

  • 利用Map的内部接口Map.Entry使用iterator。

1.4 Queue

Queue接口:

  • 继承Collection

  • boolean add(E e),队列满,抛IllegalStateException / boolean offer(E e),当容量限制时,与add相同抛IllegalStateException

  • E remove(),抛NoSuchElementException / E poll(),不抛,返回null

  • E element(),抛NoSuchElementException / E peek(),不抛,返回null

Deque接口,是一个实现了双端队列数据结构的队列,即在头尾都可进行删除和新增操作;

  • 继承Queue

  • 依旧保持着“先进先出”的本质

  • 增加 xxxFirst与xxxLast方法

  • 可以被当做“栈”来使用,即“后进先出”,添加元素、删除元素都在队头进行通过push/pop两个方法来实现

  • 主要两个实现LinkedList与ArrayDeque

PriorityQueue:

  • 不同于先进先出,它可以通过比较器控制元素的输出顺序(优先级)

  • 本质上就是一个最小堆存储结构数组了

  • 通过“极大优先级堆”实现的,即堆顶元素是优先级最大的元素。算是集成了大根堆和小根堆的功能。

  • 堆的操作,主要就是两个:siftUp和siftDown,一个是向上调整堆,一个是向下调整堆。

1.5 工具类Collections

根据字符串长度的正序和倒序排序:

  • Collections.reverse(List<?> list) 反转指定列表中元素的顺序。

  • <T> Comparator<T> Collections.reverseOrder() 返回一个比较器,它强行逆转实现了 Comparable 接口的对象 collection 的自然顺序。

  • <T> Comparator<T> reverseOrder(Comparator<T> cmp) 返回一个比较器,它强行逆转指定比较器的顺序。

排序

  • Collections.sort(List<?> list)

  • Collections.sort(List<?> list, Collections.reverseOrder())

同步视图

  • <T> Collection<T> synchronizedCollection(Collection<T> c)

  • <T> Collection<T> synchronizedCollection(Collection<T> c, Object mutex)

只读视图

  • <T> Collection<T> unmodifiableCollection(Collection<? extends T> c)

其它工具

  • <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)

  • <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key)

  • <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)

  • <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)

  • <T> void fill(List<? super T> list, T obj)

  • <T> List<T> nCopies(int n, T o)

1.6 并发集合

List接口:

  • CopyOnWriteArrayList,线程安全的ArrayList

    • 使用volatile修饰数组引用:确保数组引用的内存可见性

    • 对容器修改操作进行同步:从而确保同一时刻只能有一条线程修改容器(因为修改容器都会产生一个新的容器,增加同步可避免同一时刻复制生成多个容器,从而无法保证数组数据的一致性)

    • 修改时复制容器:确保所有修改操作都作用在新数组上,原本的数组在创建过后就用不变化,从而其他线程可以放心地读。

    • 适用于读操作远远多于写操作,并且数据量较小的情况

    • 修改容器的代价是昂贵的,因此建议批量增加addAll、批量删除removeAll

    • CopyOnWrite机制

Set接口:

  • CopyOnWriteArraySet是线程安全的Set,它内部包含了一个CopyOnWriteArrayList,因此本质上是由CopyOnWriteArrayList实现的。

  • ConcurrentSkipListSet相当于线程安全的TreeSet。它是有序的Set。它由ConcurrentSkipListMap实现。

    • 它是一个有序的、线程安全的Set,相当于线程安全的TreeSet。


Map接口:

  • ConcurrentHashMap线程安全的HashMap。采用分段锁实现高效并发。

    • ConcurrentHashMap由多个Segment构成,每个Segment都包含一张哈希表。每次操作只将操作数据所属的Segment锁起来,从而避免将整个锁住。


  • ConcurrentSkipListMap线程安全的有序Map。使用跳表实现高效并发。

    • 它是一个有序的Map,相当于TreeMap。TreeMap采用红黑树实现排序,而ConcurrentHashMap采用跳表实现有序。

    • 跳表是条有序的单链表,它的每个节点都有多个指向后继节点的引用。

Queue:

  • ConcurrentLinkedQueue线程安全的无界队列。底层采用单链表。支持FIFO。

    • head、tail、next、item均使用volatile修饰,保证其内存可见性,并未使用锁,从而提高并发效率。


  • ConcurrentLinkedDeque线程安全的无界双端队列。底层采用双向链表。支持FIFO和FILO。


  • ArrayBlockingQueue数组实现的阻塞队列。

    • 内部由Object数组存储元素,构造时必须要指定队列容量。

    • 由ReentrantLock实现队列的互斥访问,并由notEmpty、notFull这两个Condition分别实现队空、队满的阻塞。

    • ReentrantLock分为公平锁和非公平锁,可以在构造ArrayBlockingQueue时指定。默认为非公平锁。

    • 队满阻塞:当添加元素时,若队满,则调用notFull.await()阻塞当前线程;当移除一个元素时调用notFull.signal()唤醒在notFull上等待的线程。

    • 队空阻塞:当删除元素时,若队为空,则调用notEmpty.await()阻塞当前线程;当队首添加元素时,调用notEmpty.signal()唤醒在notEmpty上等待的线程。


  • LinkedBlockingQueue链表实现的阻塞队列。

    • 由单链表实现,因此是个无限队列。但为了方式无限膨胀,构造时可以加上容量加以限制。

    • 分别采用读取锁和插入锁控制读取/删除 和 插入过程的并发访问,并采用notEmpty和notFull两个Condition实现队满队空的阻塞与唤醒。

    • 队满阻塞:若要插入元素,首先需要获取putLock;在此基础上,若此时队满,则调用notFull.await(),阻塞当前线程;当移除一个元素后调用notFull.signal()唤醒在notFull上等待的线程;最后,当插入操作完成后释放putLock。

    • 若要删除/获取元素,首先要获取takeLock;在此基础上,若队为空,则调用notEmpty.await(),阻塞当前线程;当插入一个元素后调用notEmpty.signal()唤醒在notEmpty上等待的线程;最后,当删除操作完成后释放takeLock。


  • LinkedBlockingDeque双向链表实现的双端阻塞队列。

2 Stream

Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。

对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)。Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。

2.1 操作类型

  • Intermediate(中间操作): 可以后面跟随零个或多个 intermediate 操作。这类操作都是惰性化的(lazy)。map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered等

  • Terminal(终止操作): 只能有一个 terminal 操作, Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果。forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator等

还有一种操作被称为 short-circuiting(短路操作):

  • 对于一个 intermediate 操作,如果它接受的是一个无限流,它可以返回一个有限的新 Stream。

  • 对于一个 terminal 操作,如果它接受的是一个无限流,但能在有限的时间计算出结果。anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit

2.2 构造

  • Stream.of(T… values):需要注意的是,不能全是null

  • Stream.empty():构造一个空流

  • Stream.iterate(BigInteger.ONE, n->n.add(BigInteger.ONE))

  • Stream.generate(new Random()::nextInt)

  • Stream.concat(list1.stream(),list2.stream())

  • IntStream.range(1, 3)

  • IntStream.rangeClosed(1, 3)

2.3 reduce

reduce的作用是把stream中的元素给组合起来。至于怎么组合起来:它需要我们首先提供一个起始种子,然后依照某种运算规则使其与stream的第一个元素发生关系产生一个新的种子,这个新的种子再紧接着与stream的第二个元素发生关系产生又一个新的种子,就这样依次递归执行,最后产生的结果就是reduce的最终产出。

运用reduce我们可以做sum,min,max,average,这些常用的reduce,stream api已经为我们封装了对应的方法。

  • reduce(T iden, BinaryOperator b): 可以将流中元素反复结合起来,得到一个值,返回 T

  • reduce(BinaryOperator b): 可以将流中元素反复结合起来,得到一个值,返回 Optional

  • reduce(U identity, BiFunction a, BinaryOperator combiner): 可以将流中元素反复结合起来,得到一个值,返回 Optional

三个参数时是最难以理解的。 分析下它的三个参数:

  • identity: 一个初始化的值;这个初始化的值其类型是泛型U,与Reduce方法返回的类型一致;注意此时Stream中元素的类型是T,与U可以不一样也可以一样,这样的话操作空间就大了;不管Stream中存储的元素是什么类型,U都可以是任何类型,如U可以是一些基本数据类型的包装类型Integer、Long等;或者是String,又或者是一些集合类型ArrayList等

  • accumulator: 其类型是BiFunction,输入是U与T两个类型的数据,而返回的是U类型;也就是说返回的类型与输入的第一个参数类型是一样的,而输入的第二个参数类型与Stream中元素类型是一样的

  • combiner: 其类型是BinaryOperator,支持的是对U类型的对象进行操作

2.4 collect

Collectors里常用搜集器

  • toList:list.stream().collect(Collectors.toList())

  • toSet:list.stream().collect(Collectors.toSet())

  • toCollection:list.stream().collect(Collectors.toCollection())

  • counting:计算流中元素的个数, list.stream().collect(Collectors.counting())

  • summingInt:对流中的元素的整数求和, list.stream().collect(Collectors.summingInt(Employee::getSalary))

  • averagingInt:对流中的元素的整数求平均值,list.stream().collect(Collectors.averagingInt(Employee::getSalary))

  • summarizingInt:对流中的元素的整数求统计值,list.stream().collect(Collectors.summarizingInt(Employee::getSalary)).getAverage()

  • joining:连接每个字符串,list.stream().map(Employee::getName).collect(Collectors.joining(“,”))

  • maxBy:根据比较器选择最大值,list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary)))

  • minBy:根据比较器选择最小值,list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary)))

  • reduce:list.stream().collect(Collectors.reduc(0, Employee::getSalary, Integer::sum))

  • collectingAndThen:list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size))

  • groupBy:根据属性对流分组,返回Map,属性为K,list.stream().collect(Collectors.groupBy(Employee::status))

  • partitiongBy:根据true/fase对流分组,返回Map,

  • toMap:toMap最少应接受两个参数,一个用来生成key,另外一个用来生成value。当key重复时,会抛出异常;当value为null时,会抛出异常,list.stream() .collect(toMap(t -> t.getId(), Function.identity(), (k1, k2) -> k1, LinkedHashMap::new))

  • toConcurrentMap: 线程安全的Map


注:以上内容收集于互联网多篇文章,在此感谢原作者们。

BY:HW-XTF

点赞
收藏
回复
5
分享
举报
浏览1481 发布于2019-10-31 03:12未知归属地
全部评论
最多点赞
最新发布
最早发布

关联阅读:跟我一起复习Java(4)

5楼回复于2019-10-31 03:32 未知归属地

关联阅读:跟我一起复习Java(3)

4楼回复于2019-10-31 03:23 未知归属地

关联阅读:跟我一起复习Java(1)

3楼回复于2019-10-31 03:14 未知归属地

感兴趣的可以一起学习啊,更多文章看楼下

2楼回复于2019-10-31 03:14 未知归属地

跟我一起复习Java的系列文章第二篇来啦

1楼回复于2019-10-31 03:13 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

目录 收起
1 集合体系
1.1 Iterator
1.2 Collection
1.3 Map
1.4 Queue
1.5 工具类Collections
1.6 并发集合
2 Stream
2.1 操作类型
2.2 构造
2.3 reduce
2.4 collect
了解社区公约,与您携手共创和谐专业的开发者社区。