Java8学习:打卡第44天
文章内容- Lambda表达式和方法引用回顾
- 构造器引用
- 数组引用
- Stream API
内容管理 :java8构造器引用
Lambda表达式和方法引用回顾在昨天的分享中,了解到Lambda表达式的作用就是创建函数式接口的实例,并且使用方法引用来更加简化Lambda表达式,但是方法引用要做到引用的方法恰当,只要创建实例之后,直接就可调取其中的方法来完成相关的操作
昨天的分享中,已经明确了这两种结构的用法,这里先来简单再回顾一下
Suppliersupply = () -> "Cfeng"; System.out.println(supply.get());
昨天提到过,消费型接口是对传入的对象进行操作,而供应型接口就是获得一个T类型的对象
上面这个例子的Lambda表达式有些许简单,再来看一个例子,其中例子中的Employee类就是之前的博客中的Employee
Employee employee = new Employee(12, "Cfeng", 2, 30); Suppliersupply = () -> employee.getDetails();//这就是常规Lambda表达式使用其他的方法的方式 System.out.println(supply.get()); //方法引用的方式 Supplier con2 = employee :: getDetails; //使用方法引用来进行优化 System.out.println(con2.get());//和C不一样,不是地址,而是地址指代的对象的字符串表示,还是有所区别
方法使用的要求
接口中的参数列表和返回值类型和调用方法的参数列表和返回值类型相同
昨天的博客中就已经提到过了,方法引用的方式有
-
类 :: 静态方法 -----例子就是 Integer :: compare
-
对象 :: 实例方法 -----例子就是上面的 employee :: getDetails
⚠上面的要求只适用于前两种情况,第三种情况不是很适合⚠️ -
类 :: 实例方法
传入的两个对象中,第一个对象是实例方法的调用者,所以就可以直接省略,写成方法引用的形式
这第三种看着好像会很疑惑,因为和普通的.引用的方式有点脱,看一个例子
使用的函数式接口为 Comparator中的int compare(T t1, T t2)
想调用的实现方法为String中的 boolean t1.compareTo(t2)
这里的参数列表是不匹配的,看看是怎么回事
Comparatorcom1 = (t1,t2) -> t1.compareTo(t2); System.out.println(com1.compare("abc", "abd")); //传入的两个对象中,第一个对象是实例方法的调用者,所以就可以直接省略,写成方法引用的形式 Comparator com = String :: compareTo; System.out.println(com.compare("abc", "abd"));
这里通过Lambda表达式到方法引用的变化,相信你就可以知道为什么是类 :: 实例方法了;这里其实是使用传入的第一个对象来调用的实例方法,并没有违背规则
- 使用还是有要求的
那就是这里调取的方法的参数个数比functionalinterface中的abstract方法少一个,并且抽象方法参数类表中的第一个必须是实例方法的类类型的
- 那为什么要使用类名来调用呢?
这是因为调取的时候调取实例方法的对象是该类的一个对象,并且不能使用 对象 :: 实例方法,因为这里是因为如果使用对象那么这里的参数就只能有一个,而不是两个,所以不能使用第二种方式
构造器引用其实构造器引用就是方法引用的一个特例,既然我们可以通过类名来调用一个静态方法,那么也可以使用类名来调用一个类的构造器,只是注意写法 :类名 :: new
但是这里需要注意的地方就是接口中的方法的参数列表和构造器的参数列表需要相同
抽象方法的返回值类型就是构造的类类型的
举几个例子来说明一下
- 空参构造器
Supplieremp = () -> new Employee(); emp.get(); //换成方法引用的方式 Supplier emp1 = Employee :: new; emp1.get();
这里获取的对象就是一个创建的Employee对象,为了检验是否执行,在构造器中加一个打印语句,就可以执行
- 含参构造器
这里可以使用Function接口R apply(T t) ; 传入一个T类型的t,返回一个R类型的对象
Functionfunc1 = name -> new Employee(name); System.out.println(func1.apply("张三")); //看一下方法引用的方式 Function func = Employee :: new; System.out.println(func.apply("李四"));
打印的结果是
0 张三 0 0.0
0 李四 0 0.0
java可以自动识别相应的构造器来进行方法引用,所以就和之前的一样的
同理,这里还可以找到其他的含有多个参数的接口方法,比如BiFunction
Functionfunc1 = name -> new Employee(name); System.out.println(func1.apply("张三")); //看一下方法引用的方式 Function func = Employee :: new; System.out.println(func.apply("李四")); BiFunction member3 = (name,age) -> new Employee(name, age); System.out.println(member3.apply("王五", 30)); //使用方法引用来做 BiFunction member = Employee :: new; System.out.println(member.apply("孙六", 27));
运行之后的输出结果
数组引用0 张三 0 0.0
0 李四 0 0.0
0 王五 30 0.0
0 孙六 27 0.0
其实就是构造器引用,因为数组其实也是一种特殊的类,直接举例子看一下就可
Functioninstance = lenth -> new int[lenth]; System.out.println(Arrays.toString(instance.apply(5))); //使用数组引用 Function instance1 = int[] :: new; System.out.println(Arrays.toString(instance1.apply(6)));
输出的结果是
[0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0]
所以数组引用就可以看作是构造器引用,方式都是类似的
Stream APIjava8两个最重要的改变,一个是引入了Lambda表达式,另外一个就是引入了Stream API
- 什么是Stream API?
String API 在java.until中
String 是java8中处理集合的关键抽象概念,可以指定你希望对集合进行的操作,可以执行复杂的查找,过滤,映射操作,使用Stream API 对集合进行操作,就类似使用数据库进行数据库查询,也就是Stream API提供了高效使用数据的方式
- 为什么要使用Stream API?
实际开发中,我们需要从数据库中获取数据,比如在前台想要直接获取最近三个月的数据,那么会将命令发送到java处理层,但是java层原来的数据处理能力很弱,进入连接的数据库中进行相关数据的过滤,所以就只能使用MySOL和Oracle等数据库,因为其他的数据库不能自己进行数据的操作,要在java层面处理;引入了Stream API之后这里就可以使用其他的NoSQL数据源比如MongDB和Radis
- Stream和Collection的区别?
Collection是一种静态的内存结构,而Stream是有关于计算的,前者面向内存,后者面向CPU,通过CPU进行计算
- Stream的特点
Stream是数据的渠道,用来操作数据源所生成的元素序列
1 : Stream自己不会存储数据,只是计算,类似于Itreator ⛺️
2 : Stream不会改变源对象,相反会返回一个持有结果的新Stream ,类似于String类 ⛺️
3 : Stream操作是延迟执行的,它们会等到需要结果时才执行【很实用】
- 操作Stream的三个步骤
- 创建Stream :一个数据源,获取一个流
- 中间操作 :中间操作链,对数据源的数据进行处理
- 终止操作(终端操作) 一旦执行终止操作,就执行中间擦欧总链,并产生结果,之后,不能再使用 — 意味着如果想用需要再重新写一个流
今天时间有点紧,对于Stream的操作实例明天会和大家详细分析



