Java基础入门-17-【集合进阶(Stream流&方法引用)】
- 26、集合进阶(Stream流&方法引用)
-
- 1.不可变集合
- 2.Stream流
- 3.方法引用
26、集合进阶(Stream流&方法引用)
1.不可变集合
List出错问题解决
:Files->Settings->Build->Compiler->Java Compiler->Project bytecode version:17版本或者9版本以上
1.1 什么是不可变集合
是一个长度不可变,内容也无法修改的集合
1.2 使用场景
如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
当集合对象被不可信的库调用时,不可变形式是安全的。
简单理解:
不想让别人修改集合中的内容
比如说:
1,斗地主的54张牌,是不能添加,不能删除,不能修改的
2,斗地主的打牌规则:单张,对子,三张,顺子等,也是不能修改的
3,用代码获取的操作系统硬件信息,也是不能被修改的
1.3 不可变集合分类
- 不可变的list集合
- 不可变的set集合
- 不可变的map集合
1.4 不可变的list集合
import java.util.Iterator;
import java.util.List;
public class ImmutableDemo1 {
public static void main(String[] args) {
/*
创建不可变的List集合
"张三", "李四", "王五", "赵六"
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
List<String> list = List.of("张三", "李四", "王五", "赵六");
System.out.println(list.get(0));
System.out.println(list.get(1));
System.out.println(list.get(2));
System.out.println(list.get(3));
//增强for遍历
System.out.println("-------------------增强for遍历---------------------");
for (String s : list) {
System.out.println(s);
}
System.out.println("-------------------迭代器遍历---------------------");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
System.out.println(s);
}
System.out.println("-------------------普通for遍历---------------------");
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
//list.remove("李四");
//list.add("aaa");
//list.set(0,"aaa");
}
}
1.5 不可变的Set集合
import java.util.Iterator;
import java.util.Set;
public class ImmutableDemo2 {
public static void main(String[] args) {
/*
创建不可变的Set集合
"张三", "李四", "王五", "赵六"
细节:
当我们要获取一个不可变的Set集合时,里面的参数一定要保证唯一性
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Set<String> set = Set.of("张三", "李四", "王五", "赵六");
System.out.println("-------------------增强for遍历---------------------");
for (String s : set) {
System.out.println(s);
}
System.out.println("-------------------迭代器遍历---------------------");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
System.out.println(s);
}
System.out.println("----------------------------------------");
//set.remove("王五");
}
}
1.6 不可变的Map集合
1.6.1:键值对个数小于等于10
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class ImmutableDemo3 {
public static void main(String[] args) {
/*
创建Map的不可变集合
细节1:
键是不能重复的
细节2:
Map里面的of方法,参数是有上限的,最多只能传递20个参数,10个键值对
细节3:
如果我们要传递多个键值对对象,数量大于10个,在Map接口中还有一个方法
*/
//一旦创建完毕之后,是无法进行修改的,在下面的代码中,只能进行查询操作
Map<String, String> map = Map.of("张三", "南京", "李四", "北京", "王五", "上海",
"赵六", "广州", "孙七", "深圳", "周八", "杭州",
"吴九", "宁波", "郑十", "苏州", "刘一", "无锡",
"陈二", "嘉兴");
System.out.println("-------------------增强for遍历---------------------");
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + " = " + value);
}
System.out.println("-------------------entrySet遍历---------------------");
Set<Map.Entry<String, String>> entries = map.entrySet();//获取到所有的键值对对象
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " = " + value);
}
System.out.println("-------------------lambda表达式遍历---------------------");
map.forEach(new BiConsumer<String, String>() {
@Override
public void accept(String key, String value) {
System.out.println(key + " = " + value);
}
});
}
}
1.6.2:键值对个数大于10
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
public class ImmutableDemo4 {
public static void main(String[] args) {
/*
创建Map的不可变集合,键值对的数量超过10个
*/
//1.创建一个普通的Map集合
HashMap<String, String> hm = new HashMap<>();
hm.put("张三", "南京");
hm.put("李四", "北京");
hm.put("王五", "上海");
hm.put("赵六", "北京");
hm.put("孙七", "深圳");
hm.put("周八", "杭州");
hm.put("吴九", "宁波");
hm.put("郑十", "苏州");
hm.put("刘一", "无锡");
hm.put("陈二", "嘉兴");
hm.put("aaa", "111");
//2.利用上面的数据来获取一个不可变的集合
//获取到所有的键值对对象(Entry对象)
Set<Map.Entry<String, String>> entries = hm.entrySet();
//把entries变成一个数组
Map.Entry[] arr1 = new Map.Entry[0];
//toArray方法在底层会比较集合的长度跟数组的长度两者的大小
//如果集合的长度 > 数组的长度 :数据在数组中放不下,此时会根据实际数据的个数,重新创建数组
//如果集合的长度 <= 数组的长度:数据在数组中放的下,此时不会创建新的数组,而是直接用
Map.Entry[] arr2 = entries.toArray(arr1);
//不可变的map集合
Map map = Map.ofEntries(arr2);
//map.put("bbb","222");//报错
System.out.println("-------------------lambda表达式遍历---------------------");
map.forEach(new BiConsumer() {
@Override
public void accept(Object key, Object value) {
System.out.println(key + " = " + value);
}
});
System.out.println("----------------------------------------");
map.forEach((key, value) -> System.out.println(key + " = " + value));
System.out.println("----------------------------------------");
//不可变的map集合
Map<Object, Object> map1 = Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0]));
//map1.put("bbb","222");//报错
//不可变的map集合
//JDK 10.0
Map<String, String> map2 = Map.copyOf(hm);
//map2.put("bbb","222");//报错
}
}
1.7 不可变的Map集合-------总结
2.Stream流
2.1 体验Stream流【理解】
案例需求
按照下面的要求完成集合的创建和遍历
- 创建一个集合,存储多个字符串元素
- 把集合中所有以"张"开头的元素存储到一个新的集合
- 把"张"开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合
原始方式示例代码
import java.util.ArrayList;
public class StreamDemo1 {
public static void main(String[] args) {
/*
创建集合添加元素,完成以下需求:
1.把所有以“张”开头的元素存储到新集合中
2.把“张”开头的,长度为3的元素再存储到新集合中
3.遍历打印最终结果
*/
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("周芷若");
list1.add("赵敏");
list1.add("张强");
list1.add("张三丰");
System.out.println("list1 = " + list1);
//1.把所有以“张”开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for (String name : list1) {
if (name.startsWith("张")) {
list2.add(name);
}
}
System.out.println("list2 = " + list2);
//2.把“张”开头的,长度为3的元素再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for (String name : list2) {
if (name.length() == 3) {
list3.add(name);
}
}
//3.遍历打印最终的结果
System.out.println("list3 = " + list3);
/*for (String name : list3) {
System.out.println(name);
}*/
}
}
使用Stream流示例代码
import java.util.ArrayList;
public class StreamDemo2 {
public static void main(String[] args) {
/*
创建集合添加元素,完成以下需求:
1.把所有以“张”开头的元素存储到新集合中
2.把“张”开头的,长度为3的元素再存储到新集合中
3.遍历打印最终结果
*/
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("周芷若");
list1.add("赵敏");
list1.add("张强");
list1.add("张三丰");
System.out.println("list1 = " + list1);
//Stream流
list1.stream().filter(name -> name.startsWith("张"))
.filter(name -> name.length() == 3)
.forEach(name -> System.out.println(name));
}
}
Stream流的好处
- 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
- Stream流把真正的函数式编程风格引入到Java中
- 代码简洁
2.2 Stream流的常见生成方式【应用】
Stream流的思想
Stream流的作用:
结合了Lambda表达式,简化集合、数组的操作
Stream流的三类方法
- 获取Stream流
- 创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法
- 流水线上的操作
- 一次操作完毕之后,还可以继续进行其他操作
- 终结方法
- 一个Stream流只能有一个终结方法
- 是流水线上的最后一个操作
生成Stream流的方式
-
Collection体系集合
使用默认方法stream()生成流, default Stream stream()
-
Map体系集合
把Map转成Set集合,间接的生成流
-
数组
通过Arrays中的静态方法stream生成流
-
同种数据类型的多个数据
通过Stream接口的静态方法of(T… values)生成流
代码演示
public class StreamDemo {
public static void main(String[] args) {
//Collection体系的集合可以使用默认方法stream()生成流
List<String> list = new ArrayList<String>();
Stream<String> listStream = list.stream();
Set<String> set = new HashSet<String>();
Stream<String> setStream = set.stream();
//Map体系的集合间接的生成流
Map<String,Integer> map = new HashMap<String, Integer>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
//数组可以通过Arrays中的静态方法stream生成流
String[] strArray = {
"hello","world","java"};
Stream<String> strArrayStream = Arrays.stream(strArray);
//同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流
Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");
Stream<Integer> intStream = Stream.of(10, 20, 30);
}
}
2.3 Stream流的使用步骤:
Stream流的使用步骤:
① 先得到一条Stream流(流水线),并把数据放上去
② 使用中间方法对流水线上的数据进行操作
③ 使用终结方法对流水线上的数据进行操作
① 先得到一条Stream流(流水线),并把数据放上去
代码展示
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class StreamDemo3 {
public static void main(String[] args) {
/*
单列集合 default Stream<E> stream() Collection中的默认方法
双列集合 无 无法直接使用Stream流
数组 public static <T> Stream<T> stream(T[] array) Arrays工具类中的静态方法
一堆零散数据 public static<T> Stream<T> of(T... values) Stream接口中的静态方法
*/
//1.单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "A", "B", "C", "D", "E", "F");
System.out.println("--------------------------------");
//获取到一条流水线,并把集合中的数据放到流水线上
Stream<String> stream1 = list.stream();
//使用终结方法打印一下流水线上的所有数据
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
//s:依次表示流水线上的每一个数据
System.out.println(s);
}
});
System.out.println("--------------------------------");
list.stream().forEach(s -> System.out.println(s));
}
}
import java.util.HashMap;
public class StreamDemo4 {
public static void main(String[] args) {
//双列集合 无 无法直接使用stream流
//1.创建双列集合
HashMap<String, Integer> hm = new HashMap<>();
//2.添加数据
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
hm.put("ddd", 444);
//3.第一种获取stream流的办法
hm.keySet().stream().forEach(s -> System.out.println(s));
//4.第二种获取stream流的办法
hm.entrySet().stream().forEach(s -> System.out.println(s));
}
}
import java.util.Arrays;
public class StreamDemo5 {
public