一、Collections
1.1 可变参数
可变参数就是一种特殊形参,定义在方法、构造器的形参列表里,格式是:数据类型... 参数名称 优点特点:可以不传数据给它;可以传一个或者同时传多个数据给它;也可以传一个数组给它。好处:常常用来灵活的接收数据。 注意事项1. 可变参数在方法内部就是一个数组2. 一个形参列表中可变参数只能有一个3. 可变参数必须放在形参列表的最后面
public class Demo {
public static void main(String[] args) {add();//可变参数可以不传参add(1);//可变参数可以传一个add(1,2);//可变参数可以传多个add1(1,2,3);
}
//计算整数的和public static void add(int ... nums){//一个形参列表中可变参数只能有一个int sum = 0;for (int i : nums) {sum += i;}System.out.println("sum=" + sum);}public static void add1(int index, int ... nums){//可变参数必须放在形参列表的最后面int sum = index;for (int i : nums) {sum += i;}System.out.println("sum=" + sum);}
}
1.2 Collections常用方法
Collections这是一个用于操作单列集合的工具类注意跟Collection的区别(Collection是单列集合的根接口) 常用方法static <T> boolean addAll(单列集合,可变参数) 批量添加元素static void shuffle(List集合) 打乱List集合元素顺序,每次调用都会打乱static <T> void sort(List集合) List集合进行自然排序static <T> void sort(List集合,比较器) List集合进行比较器排序
public class Demo {public static void main(String[] args) {//static <T> boolean addAll(单列集合,可变参数) 批量添加元素List<String> list = new ArrayList<>();Collections.addAll(list, "张三", "李四", "王五", "赵六", "钱七");System.out.println(list);System.out.println("----------------------------");
//static void shuffle(List集合) 打乱List集合元素顺序,每次调用都会打乱Collections.shuffle(list);System.out.println(list);System.out.println("----------------------------");
//static <T> void sort(List集合) List集合进行自然排序List<Integer> nums = new ArrayList<>();Collections.addAll(nums,5,9,8,5,4,0,1,2);Collections.sort(nums);System.out.println(nums);System.out.println("----------------------------");
//排自定义类对象,需要指定排序规则List<Student> stuList = new ArrayList<>();stuList.add(new Student("zhangsan", 18));stuList.add(new Student("wangwu", 22));stuList.add(new Student("zhaoliu", 21));stuList.add(new Student("lisi", 19));stuList.add(new Student("qianqi", 20));
//static<T> void sort(List集合,比较器);List集合进行比较器排序Collections.sort(stuList, ( o1, o2)-> {return o1.getAge() - o2.getAge();});System.out.println(stuList);
}
}
class Student {private String name;private int age;
public Student() {}
public Student(String name, int age) {this.name = name;this.age = age;}
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;}
@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
运行结果:[张三, 李四, 王五, 赵六, 钱七]----------------------------[张三, 赵六, 王五, 李四, 钱七]----------------------------[0, 1, 2, 4, 5, 5, 8, 9]----------------------------[Student{name='zhangsan', age=18}, Student{name='lisi', age=19}, Student{name='qianqi', age=20}, Student{name='zhaoliu', age=21}, Student{name='wangwu', age=22}]
二、Map集合
2.1 认识Map集合(适用于一一对应的一组数据)
Map集合称为双列集合,一次需要存一对数据做为一个元素,格式:[key1=value1,key2=value2,key3=value3,)
Map集合的每个元素分为两部分:key和value,key称为键,value称为值,整体叫键值对,因此Map也叫“键值对集合”
key不可重复,value可重复
2.2 Map常用方法
Map双列集合根接口,它的功能是全部双列集合都可以继承过来使用的。 常用方法V put(K key,V value) 添加/修改元素(存在k就修改value,不存在k就保存一组(k,v))int size() 获取集合的大小boolean isEmpty() 判断集合是否为空,为空返回true, 反之V get(Object key) 根据键获取对应值(根据k获取v)V remove(Object key) 根据键删除整个元素(根据k删除(k,v))boolean containsKey(Object key) 判断是否包含某个键(判断是否包含K)boolean containsValue(Object value) 判断是否包含某个值(判断是否包含v)Set<K> keySet() 获取全部键的集合Collection<V> values() 获取Map集合的全部值void clear() 清空集合
public class Demo1 {public static void main(String[] args) {//向map中存入西游四人组的编号和姓名 001-玄奘 002-悟空 003-悟能 004-悟净Map<String, String> hashMap = new HashMap<>();//V put(K key,V value) 添加元素hashMap.put("001", "玄奘");hashMap.put("002", "悟空");hashMap.put("003", "悟能");hashMap.put("004", "悟净");hashMap.put("004", "悟净11");System.out.println(hashMap);System.out.println("--------------------------");//int size() 获取集合的大小System.out.println("hashMap的长度为:" + hashMap.size());//boolean isEmpty() 判断集合是否为空,为空返回true, 反之System.out.println("hashMap是否为空:" + hashMap.isEmpty());System.out.println("--------------------------");//V get(Object key) 根据键获取对应值String s = hashMap.get("001");System.out.println("编号001对应的姓名为:" + s);System.out.println("--------------------------");//V remove(Object key) 根据键删除整个元素String remove = hashMap.remove("003");System.out.println("删除003对应的值:" + remove);System.out.println("删除003后的Map:" + hashMap);System.out.println("--------------------------");//boolean containsKey(Object key) 判断是否包含某个键boolean b = hashMap.containsKey("003");System.out.println("是否包含003:" + b);boolean b1 = hashMap.containsKey("004");System.out.println("是否包含004:" + b1);System.out.println("--------------------------");//boolean containsValue(Object value) 判断是否包含某个值boolean b2 = hashMap.containsValue("玄奘");System.out.println("是否包含玄奘:" + b2);boolean b3 = hashMap.containsValue("悟空11");System.out.println("是否包含悟空11:" + b3);System.out.println("--------------------------");//Set<K> keySet() 获取全部键的集合Set<String> strings = hashMap.keySet();System.out.println("全部键的集合为:" + strings);System.out.println("--------------------------");//Collection<V> values() 获取Map集合的全部值Collection<String> values = hashMap.values();System.out.println("Map集合的全部值:" + values);System.out.println("--------------------------");//void clear() 清空集合hashMap.clear();System.out.println("清空集合后的Map:" + hashMap);
}
}
2.3 Map集合遍历
2.3.1 遍历方式一
遍历方式1: 先获取Map集合全部的键,再通过遍历键来找值
public class Demo2 {public static void main(String[] args) {//1. 创建mapHashMap<String, String> map = new HashMap<>();map.put("001", "张三");map.put("002", "李四");map.put("003", "王五");map.put("004", "赵六");
//2. 各种方式进行遍历test1(map);
}
//遍历方式1: 先获取Map集合全部的键,再通过遍历键来找值private static void test1(HashMap<String, String> map) {//1. 获取map中的所有key,Set集合Set<String> keys = map.keySet();//2.获取每个keyfor (String key : keys) {//3.通过key,从map中获取对应的valueString value = map.get(key);System.out.println(key + "---" + value);}}
}
运行结果:001---张三002---李四003---王五004---赵六
2.3.2 遍历方式二
遍历方式2: 将map中的所有键值对放入一个set集合中, 然后遍历set集合拿到每个键值对, 再取里面的键值
public class Demo2 {public static void main(String[] args) {//1. 创建mapHashMap<String, String> map = new HashMap<>();map.put("001", "张三");map.put("002", "李四");map.put("003", "王五");map.put("004", "赵六");
//2. 各种方式进行遍历test2(map);
}
//遍历方式2: 将map中的所有键值对放入一个set集合中, 然后遍历set集合拿到每个键值对, 再取里面的键值private static void test2(HashMap<String, String> map) {//1.获取map中的所有entry对象(键值对),Set集合Set<Map.Entry<String, String>> entrySet = map.entrySet();//2.循环每个entry对象for (Map.Entry<String, String> entry : entrySet) {//System.out.println(entry);//3.通过entry对象获取键和值String key = entry.getKey();String value = entry.getValue();System.out.println(key + "---" + value);}
}
运行结果:001---张三002---李四003---王五004---赵六
2.3.3 遍历方式三
遍历方式3: Lambda, 使用foreach(BiConsumer bc)
public class Demo2 {public static void main(String[] args) {//1. 创建mapHashMap<String, String> map = new HashMap<>();map.put("001", "张三");map.put("002", "李四");map.put("003", "王五");map.put("004", "赵六");
//2. 各种方式进行遍历test3(map);
}//遍历方式3: Lambda, 使用foreach(BiConsumer bc)private static void test3(HashMap<String, String> map) {map.forEach((k,v) -> {System.out.println(k + "---" + v);});}
}
运行结果:001---张三002---李四003---王五004---赵六
2.4 Map集合案例
现有字符串数组如下
String[] s = {"《红楼梦》-曹雪芹","《西游记》-吴承恩","《三国演义》-罗贯中","《水浒传》-施耐庵"};
需求
请将字符串中的书名提取为Map集合的键,将作者提取为Map集合的值
并使用三种不同方式,遍历Map集合打印键值对元素内容
public class Demo3 {public static void main(String[] args) {//1. 定义字符串数组String[] bookArr = {"《红楼梦》-曹雪芹","《西游记》-吴承恩","《三国演义》-罗贯中","《水浒传》-施耐庵"};//2.定义Map集合HashMap<String, String> map = new HashMap<>();//3.循环遍历数组for (String str : bookArr) {String[] split = str.split("-");//4.将字符串数组中的元素添加到Map集合中map.put(split[0],split[1]);}//5.循环展示(使用k找v)Set<String> kays = map.keySet();System.out.println("作品" + "---" + "作者");for (String kay : kays) {String value = map.get(kay);System.out.println(kay + "---" + value);}System.out.println("------------------------------");//6.循环展示(获取所有的entry)Set<Map.Entry<String, String>> entrySet = map.entrySet();System.out.println("作品" + "---" + "作者");for (Map.Entry<String, String> entry : entrySet) {String key = entry.getKey();String value = entry.getValue();System.out.println(key + "---" + value);}System.out.println("----------------------------");//7.循环展示(使用Lambda)System.out.println("作品" + "---" + "作者");map.forEach((key,value) ->{System.out.println(key + "---" + value);});
}
}
运行结果:作品-----------作者《三国演义》---罗贯中《红楼梦》---曹雪芹《西游记》---吴承恩《水浒传》---施耐庵
2.5 HashMap集合的底层原理
/* 需求:创建一个HashMap集合,键是学生对象(Student),值是籍贯(String)。存储三个键值对元素,并遍历 */
public class Demo4 {public static void main(String[] args) {//1. 创建一个Map集合HashMap<Student, String> map = new HashMap<>();//2. 存储三个学生和地址map.put(new Student("张三", 23), "北京");map.put(new Student("李四", 24), "上海");map.put(new Student("王五", 25), "广州");map.put(new Student("王五", 25), "广州");//3. 遍历打印map.forEach((key,value)->{System.out.println(key + "---" + value);});}
}
class Student {private String name;private int age;
public Student() {}
public Student(String name, int age) {this.name = name;this.age = age;}
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;}
@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
@Overridepublic 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 && Objects.equals(name, student.name);}
@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
运行结果:Student{name='张三', age=23}---北京Student{name='李四', age=24}---上海Student{name='王五', age=25}---广州
2.6 LinkedHashMap 底层原理
//存取有序
public class Demo5 {public static void main(String[] args) {//创建LinkedHashMapMap<Object, Object> map = new LinkedHashMap<>();//保存数据map.put("悟空", "001");map.put("八戒", "002");map.put("沙僧", "003");map.put("白龙马", "004");//观察顺序map.forEach((key,value)->{System.out.println(key + "---" + value);});}
}
2.7 TreeMap
2.7.1 TreeMap案例
需求:创建一个TreeMap集合,键是老师对象(Teacher),值是籍贯(String)。
学生属性姓名和年龄,按照年龄进行排序并遍历。
1、让类实现Comparable接口,重写比较规则。
public class Demo6 {private String put;
public static void main(String[] args) {//创建集合Map<Teacher, String> map = new TreeMap<>();map.put(new Teacher("张三", 21), "河北");map.put(new Teacher("李四", 20), "山东");map.put(new Teacher("王五", 19), "山西");map.put(new Teacher("赵六", 21), "河南");
map.forEach((k, v) -> {System.out.println(k + "-----" + v);});}
}
class Teacher implements Comparable<Teacher>{private String name;private int age;
public Teacher() {}
public Teacher(String name, int age) {this.name = name;this.age = age;}
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;}
@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +'}';}
@Overridepublic int compareTo(Teacher o) {if(this.age != o.age){return this.age - o.age;}else {return this.name.compareTo(o.name);}
}
}
运行结果: Teacher{name='王五', age=19}-----山西Teacher{name='李四', age=20}-----山东Teacher{name='张三', age=21}-----河北Teacher{name='赵六', age=21}-----河南
2、TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。
public class Demo8 {private String put;
public static void main(String[] args) {//创建集合Map<Teacher1, String> map = new TreeMap<>(new Comparator<Teacher1>() {@Overridepublic int compare(Teacher1 o1, Teacher1 o2) {if(o1.getAge()==o2.getAge()){return o1.getName().compareTo(o2.getName());}else {return o1.getAge()-o2.getAge();}}});map.put(new Teacher1("张三", 21), "河北");map.put(new Teacher1("李四", 20), "山东");map.put(new Teacher1("王五", 19), "山西");map.put(new Teacher1("赵六", 21), "河南");
map.forEach((k, v) -> {System.out.println(k + "-----" + v);});}
}
class Teacher1 {private String name;private int age;
public Teacher1() {}
public Teacher1(String name, int age) {this.name = name;this.age = age;}
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;}
@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +'}';}
}
运行结果: Teacher{name='王五', age=19}-----山西Teacher{name='李四', age=20}-----山东Teacher{name='张三', age=21}-----河北Teacher{name='赵六', age=21}-----河南
2.8 集合的嵌套(集合中的元素又是一个集合)
要求在程序中记住如下省份和其对应的城市信息,记录成功后,要求可以查询出湖北省的城市信息。
数据
江苏省 = "南京市","扬州市","苏州市","无锡市","常州市"
湖北省 = "武汉市","孝感市","十堰市","宜昌市","鄂州市"
河北省 = "石家庄市","唐山市","邢台市","保定市","张家口市"
分析: 定义一个Map集合,键用表示省份名称,值表示城市名称,注意:城市会有多个。 Map<String,List<String>> 根据“湖北省”这个键获取对应的值展示即可。
public class Demo7 {public static void main(String[] args) {//1.创建一个Map集合,key是一个字符串,value是一个list集合HashMap<String, List<String>> map = new HashMap<>();//2.向Map集合中添加江苏省和其对应的城市List<String> list1 = new ArrayList<>();Collections.addAll(list1,"南京市","扬州市","苏州市","无锡市","常州市");map.put("江苏省",list1);//3.向Map集合中添加河北省和其对应的城市List<String> list2 = new ArrayList<>();Collections.addAll(list2,"石家庄市","唐山市","邢台市","保定市","张家口市");map.put("河北省",list2);//4.向Map集合中添加湖北省和其对应的城市List<String> list3 = new ArrayList<>();Collections.addAll(list3,"武汉市","孝感市","十堰市","宜昌市","鄂州市");map.put("湖北省",list3);
System.out.println(map);
//5.根据“湖北省”这个键获取对应的值展示即可。List<String> list = map.get("湖北省");System.out.println(list);}
}
运行结果:{江苏省=[南京市, 扬州市, 苏州市, 无锡市, 常州市], 湖北省=[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市], 河北省=[石家庄市, 唐山市, 邢台市, 保定市, 张家口市]}[武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市]
三、Stream流
3.1 获取Stream流
使用流程集合/数组/…---->获取Stream流---->对流中的数据进行各种操作---->结果获取(排序、过滤、去重等等) (收集、打印、统计) 如何获取Stream流Collection集合:单列集合都支持一个stream()方法,它可以直接获取集合的Stream流数组:Arrays.stream(数组)零散数据:Stream.of(T... values)Map双列集合并没有提供直接获取Stream流的方法,他需要间接获取
public class Demo2 {public static void main(String[] args) {//"玄奘", "悟空", "悟能", "悟净"ArrayList<String> list = new ArrayList<>();list.add("玄奘");list.add("悟空");list.add("悟能");list.add("悟净");
//1、Collection集合: 单列集合都支持一个stream()方法,它可以直接获取集合的Stream流Stream<String> stream1 = list.stream();
//2、数组:Arrays.stream(数组)String[] arr = {"玄奘", "悟空", "悟能", "悟净"};Stream<String> stream2 = Arrays.stream(arr);
//3、零散数据:Stream.of(T... values)Stream<String> stream3 = Stream.of("玄奘", "悟空", "悟能", "悟净");
//4、Map:双列集合并没有提供直接获取Stream流的方法,他需要间接获取Map<String, String> map = new HashMap<>();map.put("001", "玄奘");map.put("002", "悟空");map.put("003", "悟能");map.put("004", "悟净");//可以从map中获取所有的entrySet<Map.Entry<String, String>> entrySet = map.entrySet();Stream<Map.Entry<String, String>> stream4 = entrySet.stream();
}
}
3.2 Stream流常见的中间方法
中间方法对stream流进行操作的方法, 他们调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。 常见的中间方法Stream<T> filter(Predicate<? super T> p) 按照规则过滤,保留满足条件的元素Stream<T> sorted() 升序排序Stream<T> sorted(Comparator<? super T> c) 按照规则排序Stream<T> limit(long maxSize) 截取Stream<T> skip(long n) 跳过Stream<R> map(Function<? super T, extends R> mapper) 对元素进行加工,并返回对应的新流Stream<T> distinct() 去重static <T> Stream<T> concat(Stream a,Stream b) 合并流
public class Demo3 {public static void main(String[] args) {List<Integer> list = List.of(61, 57, 66, 77, 88, 44, 100, 89, 97, 47, 70);//需求1: 找出所有及格的分数,并打印System.out.println("========及格的分数=========");list.stream().filter(integer-> integer >= 60).forEach(System.out::println);
//需求2: 找出所有及格的分数, 正序排列, 打印输出System.out.println("=======所有及格的分数正序排列==========");list.stream().filter(integer-> integer >= 60).sorted().forEach(System.out::println);
//需求3: 找出所有及格的分数, 倒序排列, 打印输出System.out.println("=======所有及格的分数倒序排列==========");list.stream().filter(integer-> integer >= 60).sorted((o1, o2) ->o1<o2 ? 1 : -1).forEach(System.out::println);
//需求4: 找出所有及格的分数, 倒序排列, 取前3名, 打印输出System.out.println("=======找出所有及格的分数, 倒序排列, 取前3名==========");list.stream().filter(integer-> integer >= 60).sorted((o1, o2) ->o1<o2 ? 1 : -1).limit(3).forEach(System.out::println);
//需求5: 找出所有及格的分数, 倒序排列, 取前4-6名, 打印输出System.out.println("=======所有及格的分数, 倒序排列, 取前4-6名==========");list.stream().filter(integer-> integer >= 60).sorted((o1, o2) ->o1<o2 ? 1 : -1).skip(3).limit(3).forEach(System.out::println);
//需求6: 找出所有及格的分数, 倒序排列, 取前4-6名, 将每个人的分数加10分, 打印输出System.out.println("=======所有及格的分数, 倒序排列, 取前4-6名,每个人的分数加10分==========");list.stream().filter(e-> e >= 60).sorted((o1,o2) -> o1 < o2 ? 1 : -1).skip(3).limit(3).map(integer-> integer+10).forEach(System.out::println);//需求7: 将下面两个集合中的元素进行合并System.out.println("=======合并==========");String[] arr1 = {"张三", "李四", "王五", "赵六", "田七"};Stream<String> stream1 = Arrays.stream(arr1);ArrayList<String> list1 = new ArrayList<>();list1.add("吉吉");list1.add("毛毛");Stream<String> stream2 = list1.stream();Stream.concat(stream1, stream2).forEach(System.out::println);
}
}
3.2 Stream流常见的终结方法
终结方法调用完成后,不会返回新Stream了,没法继续使用流了。它的作用是用来收集Stream流的结果转回到集合或者数组中去返回。 常见方法R collect(Collector collector); 将流中数据收集到指定集合,参数传递Collectors工具类调用对应方法Collectors.toList()Collectors.toSet()Collectors.toMap()Object[] toArray();把流处理后的结果收集到一个数组中去
public class Demo5 {public static void main(String[] args) {List<Teacher> list = List.of(new Teacher("玄奘", 60, 165.5),new Teacher("悟空", 50, 175.5),new Teacher("悟空", 50, 175.5),new Teacher("悟能", 55, 145.5),new Teacher("悟净", 40, 185.5));
//1. 请找出身高超过170的教师, 并放到一个新数组中Object[] array = list.stream().filter(e -> e.getHeight() > 170).toArray();System.out.println(Arrays.toString(array));
//2. 请找出身高超过170的教师, 并放到一个新List集合中List<Teacher> list1 = list.stream().filter(e -> e.getHeight() > 170).collect(Collectors.toList());System.out.println(list1);
//3. 请找出身高超过170的教师, 并放到一个新Set集合中Set<Teacher> teacherSet = list.stream().filter(e -> e.getHeight() > 170).collect(Collectors.toSet());System.out.println(teacherSet);//4. 请找出所有的教师的姓名和身高, 放到一个新Map集合中Map<String, Double> map = list.stream().distinct().collect(Collectors.toMap(teacher-> teacher.getName() , teacher -> teacher.getHeight()));System.out.println(map);}
}
class Teacher {private String name;private int age;private double height;
public Teacher() {}
public Teacher(String name, int age, double height) {this.name = name;this.age = age;this.height = 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;}
@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Teacher teacher = (Teacher) o;return age == teacher.age && Double.compare(teacher.height, height) == 0 && Objects.equals(name, teacher.name);}
@Overridepublic int hashCode() {return Objects.hash(name, age, height);}
@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +", height=" + height +'}';}
}
运行结果:[Teacher{name='悟空', age=50, height=175.5}, Teacher{name='悟空', age=50, height=175.5}, Teacher{name='悟净', age=40, height=185.5}][Teacher{name='悟空', age=50, height=175.5}, Teacher{name='悟空', age=50, height=175.5}, Teacher{name='悟净', age=40, height=185.5}][Teacher{name='悟空', age=50, height=175.5}, Teacher{name='悟净', age=40, height=185.5}]{悟能=145.5, 悟空=175.5, 玄奘=165.5, 悟净=185.5}