集合概述
数组可以保存多个对象,但在某些情况下无法确定要保存多少个对象,此时数组不再适用,因为数组长度不可变。为了保存这些数目不确定的对象,Java提供了一系列特殊的类,统称为集合,集合可以存储任意类型的对象,并且长度可变。Java中有一种特殊的类,这种类实现了collection接口和Map接口,被统称为集合。
-
Collection:单列集合的跟接口,用于存储一系列符合某种规则的元素。Collection集合有两个重要的子接口List和Set,其中List集合的特点是元素有序,可以重复,Set集合特点是元素无序不可重复,List接口主要实现类有ArratList(封装一个长度可变的数组)和LinkList(双向循环链表);Set接口的主要实现类有HashSet和TreeSet
-
Map:双列集合根接口,用于存储具有键和值映射关系元素,其中键是唯一的,Map接口主要实现类有HashMap(底层是数组+链表)和TreeMap(底层是二叉树)
List接口
List接口继承自Collection接口,是单列集合的一个重要的分支,习惯性的吧实现了List接口的对象称为List集合,在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储,在程序中可以通过索引(类似于数组元素下标)来访问集合中的指定元素。
-
ArrayList集合
public class Demo12 { public static void main(String[] args) { List list=new ArrayList(); //向集合中添加元素 list.add("a"); list.add("b"); list.add("c"); System.out.println("集合的长度"+list.size()); System.out.println("删除第2个元素"+list.remove(1)); System.out.println("集合的长度"+list.size()); System.out.println("第2个元素是"+list.get(1)); //删除集合中所有元素 list.clear(); } }
-
LinkedList集合
ArrayList集合在查询元素的时候速度比较快,但是增删元素效率较低,所以List接口提供的另一个实现类LinkedList。
public class Demo13 { public static void main(String[] args) { LinkedList list=new LinkedList(); list.add("a"); list.add("b"); list.add("c"); System.out.println(list); list.offer("d");//向集合尾部追加元素 list.push("f");//向集合头部添加元素 Object o=list.peek(); System.out.println(o);//获取第一个元素 list.removeFirst();//删除集合第一元素 list.pollLast();//删除集合最后第一元素 } }
Collection集合遍历
遍历是为了通过访问每个节点然后取出里面的值
-
Itetator(迭代器)遍历集合
public class Demo14 { public static void main(String[] args) { ArrayList list=new ArrayList(); list.add("a"); list.add("b"); list.add("c"); Iterator iterator=list.iterator(); while (iterator.hasNext()){//判断是否存在下一个元素 Object obj=iterator.next();//取出集合中的元素 System.out.println(obj); //使用JDK8增加的forEachRemaining(consumer action)方法遍历集合 it.forEachRemaining(obj->System.out.println(obj)) } } }
-
foreach遍历集合
public class Demo14 { public static void main(String[] args) { ArrayList list=new ArrayList(); list.add("a"); list.add("b"); list.add("c"); Iterator iterator=list.iterator(); //foreach循环遍历集合 for (Object x:list){ System.out.println(x); //使用JDK8增加的forEach(consumer action)方法遍历集合 list.forEach(obj-> System.out.println(obj)); } } } }
Set接口
Set接口和List接口一样,同样继承自Collection接口,并没有对功能进行扩充,只是比Collection接口更加严格,与List接口不同的是,集合中的元素无序,并且以某种规则保证存入元素不出现重复。Set接口主要有两个实现类HashSet和TreeSet,其中HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能,TreeSet是以二叉树的方式来存储元素,它可以和实现对集合中远元素进行排序,一定保证是同一种数据类型才能程序正常运行。
-
HashSet集合
public class Demo02 { public static void main(String[] args) { HashSet set =new HashSet(); set.add("jack"); set.add("eve"); set.add("Rose"); set.add("Rose");//即便添加了重复的元素但是还是输出一个 set.forEach(o -> System.out.println(o)); } }
-
TreeSet集合
public class Demo03 { public static void main(String[] args) { TreeSet ts=new TreeSet(); ts.add(3); ts.add(9); ts.add(1); ts.add(12); System.out.println("首元素为"+ts.first()); System.out.println("尾部元素为"+ts.last()); //删除第一个元素 Object first=ts.pollFirst(); System.out.println("删除第一个元素是"+first); System.out.println("删除第一个元素后TreeSet集合变为"+ts); } } //自然排序(自定义数据类型排序,比如学生类) public class Teacher implements Comparable{ String name; int age; public Teacher(String name, int age) { this.name = name; this.age = age; } //重写Object类的 toString()方法 public String toString() { return name+":"+age; } @Override //重写CompareTo接口的compareTo()方法 //先比较年龄后比较姓名 public int compareTo(Object o) { Teacher s= (Teacher) o; if(this.age-s.age>0){ return 1; } if(this.age-s.age==0){ return this.name.compareTo(s.name); } return -1; } public static void main(String[] args) { TreeSet ts=new TreeSet(); ts.add(new Teacher("jack",19)); ts.add(new Teacher("jack",19)); ts.add(new Teacher("mom",22)); ts.add(new Teacher("dad",18)); System.out.println(ts); } }
Map接口
Map接口是双列集合,用于存储具有键和值映射关系元素,其中键对象是唯一的,Map接口主要实现类有HashMap和TreeMap,HashMap是Map接口的一个实现类,该集合的键和值允许为空,但键不能重复,且集合中的元素是无序的,TreeMap也是存储具有键和值映射关系元素,不过不允许出现重复的键,所有的键按照某种顺序排列,
-
HashMap集合
public class Demo04 { public static void main(String[] args) { Map map=new HashMap(); //如果想保证存入和取出的顺序一致,则把HashMap替换为LinkedHashMap(因为底层是双向链表) map.put("1904412121","lan"); map.put("1904412125","chen"); map.put("1904412103","xie"); map.put("1904412103","zhang"); //查看键对象是否存在 System.out.println(map.containsKey("1")); //获取指定键对象映射的值 System.out.println(map.get("1")); //获取集合中的键对象和值对象集合 System.out.println(map.keySet()); System.out.println(map.values()); //替换指定键对象映射的值 map.replace("1","Tom"); System.out.println(map); //删除指定键对象映射的键值对元素 map.remove("1"); } }
-
TreeMap集合
//默认自然排序,也就是从小到大 public class Demo06 { public static void main(String[] args) { Map map=new TreeMap(); map.put("1904412121","lan"); map.put("1904412125","chen"); map.put("1904412103","xie"); map.put("1904412103","zhang"); System.out.println(map); } } //自定义比较器,从大到小排序 public class Demo06 implements Comparator{ public int compare(Object o1,Object o2){ String key1=(String) o1; String key2=(String) o2; return key2.compareTo(key1); } public static void main(String[] args) { Map map=new TreeMap(new Demo06()); map.put("1904412121","lan"); map.put("1904412125","chen"); map.put("1904412103","xie"); map.put("1904412103","zhang"); System.out.println(map); } }
Map集合遍历
//Map集合遍历,和Collection集合一样可以使用迭代器
public class Demo05 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1904412121","lan");
map.put("1904412125","chen");
map.put("1904412103","xie");
map.put("1904412103","zhang");
Set keyset=map.keySet();//获取键的集合转换为Set单列集合
Iterator it=keyset.iterator();//迭代键的集合
while (it.hasNext()){
Object key=it.next();
Object value=map.get("key");
System.out.println(key+":"+value);
}
}
}
//Map集合遍历,和Collection集合一样也可以使用forEach()方法进行遍历
public class Demo05 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1904412121","lan");
map.put("1904412125","chen");
map.put("1904412103","xie");
map.put("1904412103","zhang");
//使用forEach(BiConsumer action)方法遍历集合
map.forEach((key,value)-> System.out.println(key+":"+value));
}
}
//除以上两种方法外,还可以通过Map集合提供的value()方法遍历
public class Demo05 {
public static void main(String[] args) {
Map map=new HashMap();
map.put("1904412121","lan");
map.put("1904412125","chen");
map.put("1904412103","xie");
map.put("1904412103","zhang");
Collection value=map.values();//获得Map结合中所有的value值集合对象
value.forEach(v-> System.out.println(v));
}
}
泛型
集合虽然可以存储任意类型的对象元素,但是当把一个对象存入集合后,集合会“忘记”这个对象的类型,将该对象从集合取出的时,这个对象的编译类型就统一变成了Object类型,如果进行强制转换,就很容易出错。
public class Demo07 {
public static void main(String[] args) {
ArrayList<String> list= new ArrayList<>();
list.add("a2");
list.add("b");
list.add("c");
for(String str:list){
System.out.println(str);
}
}
}
常用工具类
-
Collections工具类
//添加排序操作 public class Demo08 { public static void main(String[] args) { ArrayList<String>list=new ArrayList<>(); Collections.addAll(list,"e","b","d","a");//添加元素 System.out.println("排序前"+list); Collections.reverse(list);//反转集合 System.out.println("反转后"+list); Collections.sort(list);//按自然顺序排列 Collections.shuffle(list);//随机打乱集合元素 Collections.swap(list,0,list.size()-1);//将两个指定元素进行互换,此处是第一个元素与最后一个元素进行互换 } } //查找替换操作 public class Demo09 { public static void main(String[] args) { ArrayList<Integer> list=new ArrayList<>(); Collections.addAll(list,-3,2,9,5,8); System.out.println("集合中最大的元素"+Collections.max(list)); System.out.println("集合中最小的元素"+Collections.min(list)); Collections.replaceAll(list,8,0);//将集合中的8用用0换掉 int index=Collections.binarySearch(list,9); System.out.println("集合通过二分查找法找元素9所在的角标为"+index); } } //更多方法可以自学API文档
-
Arrays工具类
//排序
public class Demo10 {
public static void main(String[] args) {
int[]arr={9,8,3,5,1};
Arrays.sort(arr);
prntArrays(arr);
}
public static void prntArrays(int[]arr){
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i!= arr.length-1){
System.out.print(arr[i]+",");
}else {
System.out.print(arr[i]+"]");
}
}
}
}
//查找
public class Demo10 {
public static void main(String[] args) {
int[]arr={9,8,3,5,1};
Arrays.sort(arr);
int index= Arrays.binarySearch(arr,3);
System.out.println("元素3的索引是"+index);
}}
//拷贝和替换
public class Demo10 {
public static void main(String[] args) {
int[]arr={9,8,3,5,1};
//拷贝一个指定范围内的数组
int[]copied2=Arrays.copyOfRange(arr,1,7);
//8替换集合中所有元素
Arrays.fill(arr,8);
}}
聚合操作
Lambda表达式可以简化集合和数组遍历,过滤和提取等操作,这是基于这个特性,JDK8新增了聚合操作,多数情况下我们都会涉及对集合,数组中元素进行操作,在JDK8之前都是通过普通遍历出每一个元素,然后加入if条件选择性的进行元素的查找,过滤,修改等操作,虽然可行,但是代码加多效率不高,JDK8新增了Stream接口,该接口把集合,数组转换为流的形式然后在进行各种操作,这过程就叫聚合操作。
-
创建Stream流对象(三种方法)
public class Demo12 { public static void main(String[] args) { Integer[]array={9,8,3,5,2}; //将数组转换为List集合 List<Integer>list= Arrays.asList(array); System.out.println(list); //使用集合对象的stream()方法创建Stream流对象 Stream<Integer>stream=list.stream(); stream.forEach(i-> System.out.println(i)); //使用Steram接口的of()方法方法创建Stream流对象 Stream<Integer>stream2=Stream.of(array); stream2.forEach(i-> System.out.println(i)); //使用Arrays数组工具类的stream()方法创建Stream流对象 Stream<Integer>stream3=Arrays.stream(array); stream3.forEach(i-> System.out.println(i)); } }
-
Stream流常用的方法
public class Demo13 { public static void main(String[] args) { //遍历 Stream<String> stream=Stream.of("张三","李四","张小明"); stream.forEach(System.out::println); //过滤 Stream<String> stream2=Stream.of("张三","李四","张小明"); stream2.filter(i->i.startsWith("张")&&i.length()>2)//筛选以张开头元素长度为2个元素 .forEach(System.out::println); //映射(映射为另一个流对象) Stream<String>stream3=Stream.of("a1","b1","c2"); stream3.filter(s->s.startsWith("c")) .map(String::toUpperCase) //对流进行映射,转换为大写 .sorted() //对新的流对象进行排序 .forEach(System.out::println); //截取 Stream<String> stream4=Stream.of("张三","李四","张小明"); stream4.skip(1) //跳过流的前一个元素 .limit(2)//截取流中的前两个元素 .forEach(System.out::println); //收集 Stream<String> stream5=Stream.of("张三","李四","张小明"); List<String>list=stream5.filter(i->i.startsWith("张")) .collect(Collectors.toList());//将流元素收集到List集合中 System.out.println(list); Stream<String> stream6=Stream.of("张三","李四","张小明"); String string=stream6.filter(i->i.startsWith("张")) .collect(Collectors.joining("and")); System.out.println(string); } } /* 注意: 一个Stream流对象可以进行多次中间操作, 仍会返回一个流对象,但是一个流对象只能进行一次终结操作, 一旦终结操作,这个流对象就不复存在了 */
-
Parallel Stream(平行流)
前面所介绍3种创建流的都是串行流,所谓串行流就是将源数据转换为一个流对象,然后在单线程下执行聚合操作(也就是单一管道)。而JDK8还提供了一个并行流,并行流是将数据源分为对个子流对象进行多线程操作,然后将结果汇总为一个流对象
public class Demo14 {
public static void main(String[] args) {
List<String>list= Arrays.asList("张三","李四","张小明");
//直接使用Collection接口的parallelStream()创建并行流
Stream<String>paralelStream=list.parallelStream();
//判断当前流是否是并行流
System.out.println(paralelStream.isParallel());
Stream<String>stream=Stream.of("张三","李四","张小明");
//将串行流转换为并行流
Stream<String>paralel=stream.parallel();
}
}