目录
集合体系概述
Collection集合体系编辑
迭代器
增强for循环
lambda表达式
List集合
Set集合
哈希值 就是一个int类型的数值,Java中每个对象都有一个哈希值。
TreeSet
集合的并发修改异常
集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用。
集合中存储的是元素对象的地址
集合体系结构:Collection Map
Collection :单列集合 每个元素(数据)只包含一个值。
它是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。
Collection集合特点
Collection的常用方法
Collection的遍历方式
是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator。
方法名称 | 说明 |
Interator |
返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素。 |
方法名称 | 说明 |
boolean hasNext() | 询问当前位置是否有元素存在,存在返回true,不存在返回false |
E next() | 获取当前位置的元素,并同时将迭代器对象指向下一个元素处 |
通过迭代器获取集合的元素,如果取元素越界会出现NoSuchElementException异常。
格式:
for(元素的数据类型 变量名:数组或者集合){
//在此处使用变量即可,该变量就是元素
}
增强for循环中的变量值不会影响到集合中的元素。
得益于JDK8开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合。
需要使用Collection的如下方法来完成
方法名称 | 说明 |
default void forEach(Consumer supe T> action) | 结合lambda遍历集合 |
import java.util.ArrayList;
import java.util.List;
/**
目标:掌握List系列集合的特点,以及其提供的特有方法。
*/
public class ListTest1 {
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象(有序、可重复、有索引)
List list = new ArrayList<>(); // 一行经典代码
list.add("蜘蛛精");
list.add("至尊宝");
list.add("至尊宝");
list.add("牛夫人");
System.out.println(list); // [蜘蛛精, 至尊宝, 至尊宝, 牛夫人]
// 2.public void add(int index, E element): 在某个索引位置插入元素。
list.add(2, "紫霞仙子");
System.out.println(list);
// 3.public E remove(int index): 根据索引删除元素,返回被删除元素
System.out.println(list.remove(2));
System.out.println(list);
// 4.public E get(int index): 返回集合中指定位置的元素。
System.out.println(list.get(3));
// 5.public E set(int index, E element): 修改索引位置处的元素,修改成功后,会返回原来的数据
System.out.println(list.set(3, "牛魔王"));
System.out.println(list);
}
}
特点:有序、可重复、有索引
特有方法
List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了。
链表:链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
特点:
就是一个int类型的数值,Java中每个对象都有一个哈希值。
Java中的所有对象都可以调用Object类提供的hashCode方法,返回该对象自己的哈希值。
public int hashCode():返回对象的哈希码值
对象哈希值特点
哈希表
数组快占满了会导致链表过长,查询性能降低,需要扩容。
数组+链表
哈希表详细流程
JDK8开始,当链表长度超过8,且数组长度>=6时,自动将链表转成红黑树
HashSet集合默认不能对内容一样的两个不同对象去重复
如果希望Set集合认为两个内容一样的对象是重复的,必须重写对象的HashCode()和equals()方法
基于哈希表(数组、链表、红黑树)实现的。但是它的每一个元素都额外的多了一个双链表的机制记录它前后元素的位置。
底层是基于红黑树实现的排序。
特点:不重复、无索引、可排序(默认升序排序,按照元素的大小,由小到大排序)
注意:
TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则。
public TreeSet(Comparator super E>comparator)
两种方式中,关于返回值的规则:
如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序。
package com.itheima.d3_collection_list.d5_collection_exception;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class CollectionTest1 {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("王麻子");
list.add("李麻子");
list.add("小李子");
list.add("牛爱华");
list.add("李狗蛋");
list.add("贤明");
list.add("黑虎");
System.out.println(list);
Iterator it= list.iterator();
while(it.hasNext()){
String name = it.next();
if(name.contains("李")){
it.remove();
}
}
System.out.println(list);
}
}
怎么保证遍历集合同时删除数据时不出bug
package com.itheima.d1_parameter;
import java.util.Arrays;
public class ParamTest {
public static void main(String[] args) {
test();
test(10);
test(10,20,30);
test(new int[]{10,20,30,40});
}
public static void test(int...nums){
System.out.println(nums.length);
System.out.println(Arrays.toString(nums));
System.out.println("-----------------------------");
}
}
可变参数的特点和好处
可变参数的注意事项:
Collections提供的常用静态方法
方法名称 | 说明 |
public static |
给集合批量添加元素 |
public static void shuffle(List> list) | 打乱List集合中的元素顺序 |
public static |
对List集合中的元素进行升序排序 |
public static |
对List集合中元素,按照比较器对象指定的规则进行排序 |
package com.itheima.d2_collections;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 目标:掌握Collections集合工具类的使用。
*/
public class CollectionsTest1 {
public static void main(String[] args) {
// 1、public static boolean addAll(Collection super T> c, T...elements):为集合批量添加数据
List names = new ArrayList<>();
Collections.addAll(names, "张三", "王五", "李四", "张麻子");
System.out.println(names);
// 2、public static void shuffle(List> list):打乱List集合中的元素顺序。
Collections.shuffle(names);
System.out.println(names);
// 3、 public static void sort(List list):对List集合中的元素进行升序排序。
List list = new ArrayList<>();
list.add(3);
list.add(5);
list.add(2);
Collections.sort(list);
System.out.println(list);
List students = new ArrayList<>();
students.add(new Student("蜘蛛精",23, 169.7));
students.add(new Student("紫霞",22, 169.8));
students.add(new Student("紫霞",22, 169.8));
students.add(new Student("至尊宝",26, 165.5));
// Collections.sort(students);
// System.out.println(students);
// 4、public static void sort(List list, Comparator super T> c): 对List集合中元素,按照比较器对象指定的规则进行排序
Collections.sort(students, new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o1.getHeight(), o2.getHeight());
}
});
System.out.println(students);
}
}
package com.itheima.d3_collection_list.d4_collection_set;
import java.util.Objects;
public class Student implements Comparable{
private String name;
private int age;
private double height;
// this o
@Override
public int compareTo(Student o) {
// 如果认为左边对象大于右边对象返回正整数
// 如果认为左边对象小于右边对象返回负整数
// 如果认为左边对象等于右边对象返回0
// 需求:按照年龄升序排序、
return this.age - o.age;
}
public Student() {
}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
// 只要两个对象内容一样就返回true
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Double.compare(student.height, height) == 0 && Objects.equals(name, student.name);
}
// 只要两个对象内容一样,返回的哈希值就是一样的。
@Override
public int hashCode() {
// 姓名 年龄 身高计算哈希值的
return Objects.hash(name, age, height);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
Collection只能支持对List集合进行排序
排序方式一
方法名称 | 说明 |
public static |
对List集合重元素按照默认规则排序 |
排序方式二
方法名称 | 说明 |
public static |
对List集合中元素,按照比较器对象指定的规则进行排序 |
Map是双列集合的祖宗,它的功能是全部双列集合都可以继承过来使用的。
需要存储一一对应的数据时就可以考虑使用Map集合来做
Map集合体系的特点
注意:Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的
Map的常用方法
/**
* 目标:掌握Map集合的常用方法
*/
import java.util.*;
/**
* 目标:掌握Map集合的常用方法(重点)
*/
public class MapTest2 {
public static void main(String[] args) {
// 1.添加元素: 无序,不重复,无索引。
Map map = new HashMap<>();
map.put("手表", 100);
map.put("手表", 220);
map.put("手机", 2);
map.put("Java", 2);
map.put(null, null);
System.out.println(map);
// map = {null=null, 手表=220, Java=2, 手机=2}
// 2.public int size():获取集合的大小
System.out.println(map.size());
// 3、public void clear():清空集合
//map.clear();
//System.out.println(map);
// 4.public boolean isEmpty(): 判断集合是否为空,为空返回true ,反之!
System.out.println(map.isEmpty());
// 5.public V get(Object key):根据键获取对应值
int v1 = map.get("手表");
System.out.println(v1);
System.out.println(map.get("手机")); // 2
System.out.println(map.get("张三")); // null
// 6. public V remove(Object key):根据键删除整个元素(删除键会返回键的值)
System.out.println(map.remove("手表"));
System.out.println(map);
// 7.public boolean containsKey(Object key): 判断是否包含某个键 ,包含返回true ,反之
System.out.println(map.containsKey("手表")); // false
System.out.println(map.containsKey("手机")); // true
System.out.println(map.containsKey("java")); // false
System.out.println(map.containsKey("Java")); // true
// 8.public boolean containsValue(Object value): 判断是否包含某个值。
System.out.println(map.containsValue(2)); // true
System.out.println(map.containsValue("2")); // false
// 9.public Set keySet(): 获取Map集合的全部键。
Set keys = map.keySet();
System.out.println(keys);
// 10.public Collection values(); 获取Map集合的全部值。
Collection values = map.values();
System.out.println(values);
// 11.把其他Map集合的数据倒入到自己集合中来。(拓展)
Map map1 = new HashMap<>();
map1.put("java1", 10);
map1.put("java2", 20);
Map map2 = new HashMap<>();
map2.put("java3", 10);
map2.put("java2", 222);
map1.putAll(map2); // putAll:把map2集合中的元素全部倒入一份到map1集合中去。
System.out.println(map1);
System.out.println(map2);
}
}
方法名称 | 说明 |
public Set |
获取所有键的集合 |
public V get(Object key) | 根据键获取其对应的值 |
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest1 {
public static void main(String[] args) {
Map map=new HashMap<>();
map.put("蜘蛛精",162.5);
map.put("蜘蛛精",167.9);
map.put("紫霞",169.8);
map.put("至尊宝",165.4);
map.put("牛魔王",163.9);
System.out.println(map);
Setkeys=map.keySet();
for(String key:keys){
double value=map.get(key);
System.out.println(key+"====>"+value);
}
}
}
Map.Entry提供 | 说明 |
K.getKey() | 获取键 |
V.getValue() | 获取值 |
Map提供 | 说明 |
Set | 获取所有键值对的集合 |
Set>entries =map.entrySet();
for(Map.Entryentry:entries){
String key=entry.getKey();
double value=entry.getValue();
System.out.println(key+"---->"+value);
}
方法名称 | 说明 |
default void forEach(BiConsumer super K,? super V> action) | 结合lambda遍历Map集合 |
//map.forEach(new BiConsumer() {
// @Override
// public void accept(String k, Double v) {
// System.out.println(k+"--->"+v);
// }
// });
map.forEach((k,v)->{
System.out.println(k+"--->"+v);
});
}
}
实际上:原来学的Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。
public HashSet(){
map=new HashMap<>();
}
TreeMap集合同样也支持两种方式来指定排序规则
指的是集合中的元素又是一个集合
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class StreamTest1 {
public static void main(String[] args) {
List names=new ArrayList<>();
Collections.addAll(names,"章春惠","张雨绮","张三丰","周金立","吴豪","尤晓玉");
System.out.println(names);
/*List list =new ArrayList<>();
for (String name : names) {
if(name.startsWith("张")&&name.length()==3){
list.add(name);
}
}
System.out.println(list);*/
List list2=names.stream().filter(s->s.startsWith("张")).filter(a->a.length()==3).collect(Collectors.toList());
System.out.println(list2);
}
}
获取Stream流
Collection提供的如下方法 | 说明 |
default Stream |
获取当前集合对象的Stream流 |
// 1、如何获取List集合的Stream流?
List names = new ArrayList<>();
Collections.addAll(names, "张三丰","张无忌","周芷若","赵敏","张强");
Stream stream = names.stream();
// 2、如何获取Set集合的Stream流?
Set set = new HashSet<>();
Collections.addAll(set, "刘德华","张曼玉","蜘蛛精","马德","德玛西亚");
Stream stream1 = set.stream();
stream1.filter(s -> s.contains("德")).forEach(s -> System.out.println(s));
// 3、如何获取Map集合的Stream流?
Map map = new HashMap<>();
map.put("古力娜扎", 172.3);
map.put("迪丽热巴", 168.3);
map.put("马尔扎哈", 166.3);
map.put("卡尔扎巴", 168.3);
Set keys = map.keySet();
Stream ks = keys.stream();
Collection values = map.values();
Stream vs = values.stream();
Set> entries = map.entrySet();
Stream> kvs = entries.stream();
kvs.filter(e -> e.getKey().contains("巴"))
.forEach(e -> System.out.println(e.getKey()+ "-->" + e.getValue()));
Arrays类提供的如下方法 | 说明 |
public static |
获取当前数组的Stream流 |
Stream类提供的如下方法 | 说明 |
public static |
获取当前接收数据的Stream流 |
String[] names2 = {"张翠山", "东方不败", "唐大山", "独孤求败"};
Stream s1 = Arrays.stream(names2);
Stream s2 = Stream.of(names2);
Stream常见的中间方法
import java.util.*;
import java.util.stream.Stream;
/**
* 目标:掌握Stream流提供的常见中间方法。
*/
public class StreamTest3 {
public static void main(String[] args) {
List scores = new ArrayList<>();
Collections.addAll(scores, 88.5, 100.0, 60.0, 99.0, 9.5, 99.6, 25.0);
// 需求1:找出成绩大于等于60分的数据,并升序后,再输出。
scores.stream().filter(s -> s >= 60).sorted().forEach(s -> System.out.println(s));
List students = new ArrayList<>();
Student s1 = new Student("蜘蛛精", 26, 172.5);
Student s2 = new Student("蜘蛛精", 26, 172.5);
Student s3 = new Student("紫霞", 23, 167.6);
Student s4 = new Student("白晶晶", 25, 169.0);
Student s5 = new Student("牛魔王", 35, 183.3);
Student s6 = new Student("牛夫人", 34, 168.5);
Collections.addAll(students, s1, s2, s3, s4, s5, s6);
// 需求2:找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出.
students.stream().filter(s -> s.getAge() >= 23 && s.getAge() <= 30)
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
.forEach(s -> System.out.println(s));
// 需求3:取出身高最高的前3名学生,并输出。
students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
.limit(3).forEach(System.out::println);
System.out.println("----------------------------------------------------------------");
// 需求4:取出身高倒数的2名学生,并输出。 s1 s2 s3 s4 s5 s6
students.stream().sorted((o1, o2) -> Double.compare(o2.getHeight(), o1.getHeight()))
.skip(students.size() - 2).forEach(System.out::println);
// 需求5:找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出。
students.stream().filter(s -> s.getHeight() > 168).map(Student::getName)
.distinct().forEach(System.out::println);
// distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode,equals)
students.stream().filter(s -> s.getHeight() > 168)
.distinct().forEach(System.out::println);
Stream st1 = Stream.of("张三", "李四");
Stream st2 = Stream.of("张三2", "李四2", "王五");
Stream allSt = Stream.concat(st1, st2);
allSt.forEach(System.out::println);
}
}
Stream常见的终结方法
import java.util.*;
import java.util.stream.Collectors;
/**
* 目标:Stream流的终结方法
*/
public class StreamTest4 {
public static void main(String[] args) {
List students = new ArrayList<>();
Student s1 = new Student("蜘蛛精", 26, 172.5);
Student s2 = new Student("蜘蛛精", 26, 172.5);
Student s3 = new Student("紫霞", 23, 167.6);
Student s4 = new Student("白晶晶", 25, 169.0);
Student s5 = new Student("牛魔王", 35, 183.3);
Student s6 = new Student("牛夫人", 34, 168.5);
Collections.addAll(students, s1, s2, s3, s4, s5, s6);
// 需求1:请计算出身高超过168的学生有几人。
long size = students.stream().filter(s -> s.getHeight() > 168).count();
System.out.println(size);
// 需求2:请找出身高最高的学生对象,并输出。
Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(s);
// 需求3:请找出身高最矮的学生对象,并输出。
Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(ss);
// 需求4:请找出身高超过170的学生对象,并放到一个新集合中去返回。
// 流只能收集一次。
List students1 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toList());
System.out.println(students1);
Set students2 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toSet());
System.out.println(students2);
// 需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。
Map map =
students.stream().filter(a -> a.getHeight() > 170)
.distinct().collect(Collectors.toMap(a -> a.getName(), a -> a.getHeight()));
System.out.println(map);
// Object[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray();
Student[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray(len -> new Student[len]);
System.out.println(Arrays.toString(arr));
}
}