不可变集合
不可变集合:不能修改长度,和内容。
应用场景:不想让别人修改集合中的内容,只能进行查询,保证安全性。
方法:调用集合中的of方法。对map调用copyOf方法。
细节1:当我们要获取一个不可变的Set集合时,里面的参数一定要保持不重复,否则会报错。
细节2:当我们要获取一个不可变的Map集合时,除了键要保持不重复之外, 只能传递不超过20个参数(10个键值对)。
-
底层:因为一个键值对有两个值,而形参中最多只能写一个可变参数
细节3:当我们要获取一个不可变的Map集合时,可以先对map集合调用entrySet方法把键值对整体,作为对象存储到Set集合当中,然后把对这个Set集合调用toArray方法转成数组,最后把这个数组传递给ofEntries即可,因为可变参数本质也是一个数组。
Stream流
流:类似工厂流水线,经历消毒-密封-包装等步骤。
步骤:
- 先得到Stream流
- 采用Stream流中的API操作,包括中间方法(方法结束后还可以调用其他方法)和终结方法(方法结束后不能再调用其他方法,如输出打印)
Stream流获取方法
单列集合,调用collection中的默认方法stream方法
ArrayList<String> al = new ArrayList<>();
al.add("111");
al.add("222");
al.add("333");
//调用collection中默认方法stream方法获取stream流
Stream<String> stream1 = al.stream();
//用forEach遍历stream流中的元素
stream1.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
//链式编程+Lambda表达式
al.stream().forEach(s->System.out.println(s));
- 双列集合,不能获取。需要通过keySet或者entrySet转换
- 数组,可以使用数组工具类Arrays中的stream方法
- 零散数据,用Stream接口中的静态方法of进行处理,必须是同一数据类型。
细节:of方法的形参是一个可变参数,可以传递多个零散数据,也可以传递数组(因为可变参数底层就是数组)。但是数组中元素必须是引用数据类型,才能获取到数组中每个元素;如果数组中元素是基本数据类型,那么传递的数组就会被当成of方法的一个数据。底层是因为of方法的形参是泛型,因此只能传递包装类和对象。
Stream流的中间方法
注意:
- 调用中间方法会返回新的Stream流,原来的Stream流只能使用一次,用完就关闭了。因此建议用链式编程
- 修改Stream流中的数据不会影响原来集合或数组中的数据
Stream流的终结方法
终结方法:这些方法的返回值均不是Stream流,因此后续不能再调用其他方法,因此是终结方法。
collect方法
- 把收集流中的数据放到map集合中:收集到map集合中,键不能重复
- collect方法的形参需要传递一个Collector类型的对象,通过调用Collectors类中的静态方法toMap,就可以生成这个对象。
- 在toMap方法中需要传递Function接口的两个实现类对象,第一个Function接口泛型的第一个String表示Stream流中的数据类型是String,第二个String表示键的数据类型是String;第二个Function接口泛型的第一个String同理,第二个Integer表示值的数据类型是Integer
方法引用
方法引用:把已有的方法拿过来用,当做函数式接口中抽象方法的方法体。
- 应用背景:也就是我知道这里有一个函数式接口,但是我不想自己写方法体了,想直接用别人写好的,就引用别人的当作自己的方法体。
方法引用注意事项:
- 引用处必须是函数式接口
- 被引用的方法必须已经存在
- 被引用方法功能要能满足需求(废话)
- 被引用方法的形参和返回值需要和抽象方法一致。举例如下:
方法引用的分类
引用静态方法
格式:类名::静态方法
Integer::parseInt
举例:假设一个集合中有五个字符串类型的整数,把他们转换成Integer类型输出出来。
-
传统思路:把集合的数据添加到Stream流当中,然后用中间方法map进行数据类型的转换,再用终结方法forEach打印。
-
利用方法引用:因为map形参是一个函数式接口的实现类对象,因此可以直接引用parseInt方法,正好需求都是想要把String类型转换成int类型
引用成员方法
格式:
- 为什么引用处不能是静态方法:因为在静态方法中没有this关键字。比如在main方法当中引用,就是在静态方法中引用,此时`this::方法名`就会出错。理解:this关键字指代当前对象,而静态方法优于任何对象出现,不用创建对象,那么,既然都不用创建对象,自然就没有“当前对象”这个概念了。因此,this关键字无法在static方法中使用就解释得通了。
- 如果想在本类的静态方法中,调用本类的非静态方法呢?只能在本类的静态方法中,创建一个本类的对象,再通过这个对象去调用本类的静态方法。
练习:
传统思路:把集合中的数据转换成Stream流,然后用中间方法filter方法进行过滤,最后用终结方法forEach打印
-
方法引用:首先中间方法处形参需要传递函数式接口Predicate的实现类对象,而且假设存在一个类,这个类当中有一个成员方法,形参是字符串,返回值是布尔值,方法中处理的规则和我的需求一样,就可以使用方法引用。但实际上不存在这个方法,因此这里自己写一个类和其中的成员方法。
引用构造方法
练习:
传统思路:生成Stream流,然后用map类型进行数据转换,然后在函数式接口的实现类的对象中重写方法,实现这个从String到Student的过程。
方法引用:生成Stream流,然后用map类型进行数据转换,但我不想重写方法,可以在函数式接口处直接引用构造方法,但是想引用的构造方法形参是String,返回值是Student,没有这个构造方法。那么可以自行创建这个构造方法。我要引用的这个构造方法,形参是集合中的String,返回值是Student,如何实现这个过程是一个难点,看自己本事。
引用的构造方法如下:
因为这部分内容草草就过了,笔记做的比较粗糙~
学习资料:黑马程序员