Java集合类(Collection、Map)概述


首先,要知道Java中的集合不仅仅是指Set系列,而是(包含Set、List、Queue和Map四种体系),是用于存储数量不等的对象。
其中, Set代表无序、不可重复的集合;
List代表有序、重复的集合;
Map则代表具有映射关系的集合;
Queue代表一种队列集合;

Java集合类主要是由两个接口派生而出:CollectionMap
在这里插入图片描述

一、Collection和数组的区别

数组
长度不可变;
无法保存具有映射关系的数据;
数组元素可以是基本类型(byte,short,int,long,float,double,boolean,char)的值,也可以是对象(实际上保存的是对象的引用变量)
集合类
可以保存长度不确定的数据;
可以保存具有映射关系的数据;
集合里保存的是对象(实际上保存的是对象的引用变量)

二、遍历集合的方法

1.使用lambda表达式遍历集合

//programming=["Java","Python","C#","C++"]
programming.forEach(obj -> System.out.println("迭代集合元素:" + obj));

2.使用Iterator循环遍历Collection

//programming=["Java","Python","C#","C++"]
var it = programming.iterator(); // 获取programming集合对应的迭代器
while (it.hasNext()){
	// it.next返回的是数据类型是Object类型,因此需要强制类型转换
	var p = (String) it.next();
	System.out.println(p);
}

3.使用foreach循环遍历Collection

//programming=["Java","Python","C#","C++"]
for (var program : programming){
	var p = (String) program;
	System.out.println(p);
}		

三、使用Predicate操作集合

public class temp {

  public static void main(String[] args) {
    var programming = new HashSet<>();
    programming.add("Java");
    programming.add("Python");
    programming.add("C#");
    programming.add("C++");
    programming.add("JavaScript");
    programming.add("Vue");
    System.out.println(calculate(programming, ele -> ((String) ele).length() == 3));
    System.out.println(calculate(programming, ele -> ((String) ele).contains("C")));
  }

  public static int calculate(Collection objs, Predicate p) {
    int total = 0;
    for (var obj : objs) {
      // 使用Predicate的test()方法判断该对象是否满足Predicate指定的条件
      if (p.test(obj)) {
        total++;
      }
    }
    return total;
  }
}

四、使用Stream操作集合

独立使用stream的步骤如下:

  1. 使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder;
  2. 重复调用Builder的add()方法向流中添加多个元素;
  3. 调用Builder的build()方法获取对应的Stream;
  4. 调用Stream的聚集方法;
    (对于大部分的聚集方法,每个Stream只能执行一次,所以下面执行了两个聚集方法allMatch和map,在两个方法之间又重新定义了一个变量is1,给第二个聚集方法使用)
public static void main(String[] args) {
    var is = IntStream.builder().add(3).add(1).add(2).add(9).build();
    System.out.println("is所有元素是否都是偶数:" + is.allMatch(ele -> ele % 2 == 0));

    var is1 = IntStream.builder().add(3).add(1).add(2).add(9).build();
    var newIs = is1.map(ele -> ele * 3 + 5);
    newIs.forEach(System.out::println);
    //    is.forEach(ele -> System.out.println(ele % 2));
  }

Stream提供了大量的方法进行聚集操作,这些方法既可以是“中间的”,也可以是“末端的”。上述的allMatch就是末端操作,map是中间操作。
中间操作:允许流保持打开状态,并允许直接调用后续方法,中间方法的返回值是另外一个流;
末端方法:对流的最终操作。当对某个Stream执行末端方法后,该流将会被“消耗”,切不可再用。
所以上述的is流进行了allMatch末端操作后,被消耗,不可再次使用;

常用的中间操作:filtermapToXxxpeekdistinctsortedlimit
常用的末端方法:forEachtoArrayreduceminmaxcountanyMatchallMatchnoneMatchfindFirstfindAny

五、Set集合

1.HashSet

HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

  • 不能保证元素的排列顺序;
  • HashSet不是同步的,是线程不安全的;
  • 集合元素值可以是null;

2.LinkedHashSet

  • LinkedHashSet是HashSet的子类;
  • 也是根据元素的hashCode值来决定元素的存储位置,但它同时使用链表维护元素的次序。这样是的元素看起来是以插入的顺序保存的;
  • 线程不安全;
  • 集合元素值可以是null;

3.TreeSet

  • TreeSet是SortedSet接口的实现类,可以确保集合元素处于排序状态;
  • 采用红黑树的数据结构来存储集合元素;
  • 线程不安全;
  • 自然排序 自然排序的对象要实现Comparable接口,而且应该是同一个类的多个实例;
  • 定制排序 在创建TreeSet对象时,提供一个Comparator对象与该TreeSet集合关联,由Comparator对象负责集合元素的排序逻辑;
    (0:相等;负整数:前者小于后者;正整数:前者大于后者)

4.EnumSet

  • EnumSet中的所有元素都必须是指定枚举类型的枚举值
  • 元素有序,以枚举值在Enum类内的定义顺序来决定集合元素的顺序
  • 在内部以向量的形式存储,紧凑高效,占用内存小,运行效率高
  • 不允许加入null元素
  • 线程不安全

5.Set实现类的选择

性能:EnumSet > HashSet > TreeSet
需要一个保持排序的Set:TreeSet
遍历:LinkedHashSet > HashSet
即一般情况下选HashSet,需要排序TreeSort,强调遍历LinkedHashSet枚举EnumSet

六、List集合

1.ArrayList(基于数组的线性表)

  • 封装了一个动态的,允许再分配的Object[]数组,initialCapacity参数默认值为10
  • 对于所有内部基于数组的集合实现,使用随机访问的性能要比使用Iterator迭代访问的性能要好;
  • 线程不安全
  • Arrays.asList:生成Arrays的内部类ArrayList的一个实例,Arrays.ArrayList是一个固定长度的List集合,只能遍历,不能增加删除;

2.Vector

  • 与上述ArrayList类似,显著区别是:Vector线程安全,还提供了一个Stack子类,模拟“栈”;
  • 虽然Vector也是以数组的形式存储集合元素,但因为它实现了线程同步功能,加之其它原因,性能较差;

七、Queue

1.PriorityQueue

  • Queue的实现类
  • 保存队列中的元素顺序以队列元素大小排序,而不是加入队列的顺序;
  • 不允许插入null元素;
  • 自然排序
  • 定制排序
  • 对元素的要求类似于TreeSet;

2.Deque

  • 是Queue的子接口,代表一个双端队列,既可以当队列使用,也可以当栈使用;

3.ArrayDeque

  • Deque接口的实现类
    • 封装了一个动态的,允许再分配的Object[]数组,initialCapacity参数默认值为16

4.LinkedList(基于链的线性表)

  • List接口的实现类,有List集合的特点,可以根据索引来随机访问集合中的元素;
  • 实现了Deque接口,可以被当成双端队列使用,“栈”、“队列”

5.各种线性表的选择

  • 所有内部以数组作为底层实现的集合在随机访问时性能都比较好,eg. ArrayList、ArrayDeque
  • 内部以链表形式作为底层实现的集合在执行插入、删除操作时有较好的性能,eg. LinkedList
  • 提到排序的:PriorityQueue

八、Map

Set接口下有HashSetLinkedHashSetSortedSetTreeSetEnumSet等子接口和实现类;
Map接口下有HashMapLinkedHashMapSortedMapTreeMapEnumMap等子接口和实现类;
Map的类和子接口中Key集的存储形式和对应的Set集合中的元素存储形式完全相同;
从Java源码来看,Java先是实现了Map,然后通过包装一个所有value均为空对象的Map就实现了Set集合;
Map提供了一个Entry内部类来封装key-value对,而计算Entry存储时则只考虑Entry封装的key;

1.HashMap

  • 线程不安全
  • 可以使用null为key或value,最多只能有一个key-value对的key为null;

2.Hashtable(古早,和Vector一样)

  • 线程安全,性能比HashMap差;
  • 不允许使用null作为key和value;

3.LinkedHashMap

  • HashSet的子类
  • 需要维护元素的插入顺序,性能略低于HashMap;
  • 以(双向)链表维护内部元素,所以迭代访问(遍历时)有较好性能;
scores.forEach((key,value) -> System.out.println(key + "-->" + value));

4.Properties

  • Hashtable的子类
  • 处理属性文件(ini、xml)

5.TreeMap

  • 自然排序
  • 定制排序

6.WeakHashMap

  • HashMap的key保存了对实际对象的强引用
  • WeakHashMap保存了对实际对象的弱引用

7.IdentityHashMap

  • 与HashMap类似
  • 不同点:在IdentityHashMap中,当且仅当两个key严格相等(key1 == key2)时,才认为两个key相等;在HashMap中,只要key1和key2通过equals方法比较返回true,且hashCode值相等,才认为两个key相等;

8.Map实现类的选择

性能:EnumMap > HashMap(IdentityHashMap) > LinkedHashMap > Hashtable > TreeMap
强调排序:TreeMap > HashMap

九、操作集合的工具类:Collections

  1. 排序
  2. 查找替换
  3. 同步控制synchronizedXxx
  4. 设置不可变集合:emptyXxxsingletonXxxunmodifiableXxx、(Java9新增的:Set、List、Map的of方法)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值