第十四章 Iambda表达式和流处理
14.1:Iambda表达式简介
Iambda表达式可以用非常少的代码来实现抽象方法。 Iambda表达式不能独立执行,因此必须是西安函数式接口,并返回一个函数式接口的对象。 Iambda表达式的语法特殊的 语法格式如下
()->结果表达式
参数 ->结果表达式
(参数1,参数2, ....参数n)->结果表达式
// () -> {代码块}
// 这个方法 按照 这样的代码来实现
//简单总结:操作左侧的式方法残念书,操作符右侧是方法体
Iambda表达式实现函数式接口
Iambda表达式可以实现函数式接口,
1.函数式接口
函数式接口的式京包含的一个抽象方法的接口,接口中的方法简单明了地说明了接口地,如用途线程解耦Runnable,动作时间监听接口,ActionListener等,开发者可以创建自定义地函数式接口 如下
interface Mylnterface{
void method();
}
//定义了一个没有方法体的抽象方法
2. Iambda表达式实现无参数抽象方法
很多函数接口的抽放方法是无参数的,如线程接口Runnable接口只有一个run()方法这样的无参抽象方法在 Iambda表达式中使用()表示代码如
本实例,直接在 Iambda表达式中创建了SayHiInterface接口对象,并制定了一个字符串作为接口方法的返回值,最后在输出语句中,pi对象就是Iambda表达式创建出的对象,当pi调用接口方法时就输出了 Iambda表达式指定的字符串
3.Iambda表达式实现也有参的抽象方法
代码如下
package 第十四章;
interface AddInterface{
int add(int a , int b );
}
public class ParamterDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//使用匿名内部类方法补全方法体(有参数)
AddInterface add1 = new AddInterface () {
public int add(int a , int b) {
return a+b ;
}
};
System.out.println("内部类:"+add1.add(3, 5));
//使用lambda表达式补全方法体 (有参数)
AddInterface add2 = (a,b) ->{ return a+b ;
};
System.out.println("lambda表达式:"+add2.add(9, 5));
}
}
在这实例中,函数式接口的抽象方法有两个参数,Iambda表达式的圆括号内也写了两个参数对应的抽象方法,注意 Iambda表达式中的参数不需要与抽象方法的参数名称相同,但是顺序必须相同
4.Iambda表达式使用代码块
当函数式接口的抽象方法需要实现复杂的逻辑而不是返回一个简单的表达式的话 ,就需要在Iambda表达式中使用代码块 Iambda表达式会自动判断返回类型释放符合抽象方法的定义
Iambda表达式调用外部变量
Iambda表达式除了可以调用定义好的参数,还可以调用表达式以外的变量,但是,这些外部变量有些可以被更改 有些则不行
1.Iambda表达式无法更改局部变量
局部变量在lambda表达式中默认被定义为final(静态)也就是说Iambda表啊但是只能调用局部变量,却不能改变其值
代码如下
package 第十四章;
interface Variablelnterface1{
void method();
}
public class VariableDemo1 {
public static void main (String []args) {
int value = 100;
Variablelnterface1 v =()->{
int num = value-90;
value = 12;
};
}
}
2.lambda表达式可以更改成员变量
成元年两式在lambda表达式中不是被final修饰的,所以lambda表达式可以改变其值
lambda表达式与异常处理
很多接口的抽象方法为了保证程序的安全性,会在定义时抛出异常,但是lambda表达式中并没有抛出异常的语法,这是因为lambda表达式会默认抛出抽象原有的异常每当此方法被调用时则需要进行异常处理
14.2方法的引用
lambda表达式还添加了一类新语法,用来一弄方法也就是方法可以作为一个对象被调用,根据不同的方法类型,方法的引用包括了引用静态方法,引用成员方法和引用构造方法等等。
引用语法如下
类名::静态方法名 //“::”是引用的意思
主要的使用方法如下
package 第十四章;
interface AddInterface1{
int add(int a ,int b );
}
public class paramterDemo1 {
static int add (int a , int b){//需要添加static变量(让这个方法变成静态方法 然后达到只能坐在本类使用)
return a+b ;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//1 paramterDemo1 pd = new paramterDemo1();//去掉static的方法
AddInterface1 add1 = paramterDemo1::add;//使用paramterDemo1中的add方法来补全方法体然而达成效果
System.out.println("方法的引用:"+add1.add(3, 5));
}
}
代码图
引用带有泛型的方法
泛型是java开发经常使用到的功能 “::”操作符支持引用泛型的方法。除了方法外,“::”操作符也支持引用带有泛型的类
引用构造方法
lambda表达式有3种引用构造方法的语句,分别是引用无参构造方法,引用有参构造方法和引用数组构造方法
1.引用无参构造方法
引用无参构造方法的语句如下
类名::new
因为构造方法与与类名相同,如果操作符左右都写类名的话,会让操作符以为是在引用与类名相同的静态方法,这昂会导致程序出现Bug,所以引用构造方法的语法使用了new关键字,操作符右侧new关键字,表示引用构造方法
这个语法有一点要注意:new关键字之后没有圆括号,也没有参数的定义。如果类中既有无参构造方法,又有有参构造方法。使用引用构造方法语句后,究竟哪一个构造方法被引用了呢,引用哪个构造方法是有函数决定的,“::”操作符会返回与抽象方法的参数结构相同的构造方法,如果找不到参数接口相同的构造方法,则会繁盛编译错误
以如下代码所示
package 第十四章;
interface Constructorslnterface2{//创建集合
ConstructorsDemo2 action();//调用有参构造方法
}
public class ConstructorsDemo2 {//测试类
public ConstructorsDemo2() {//无参构造方法
System.out.println("调用无参构造方法");//
}
public ConstructorsDemo2 (int i){//有参构造方法
System.out.println("调用有参构造方法");
}
public static void main (String []args) {//主方法//
Constructorslnterface2 a = ConstructorsDemo2::new ;//调用ConstructorsDemo2类的构造方法
ConstructorsDemo2 b =a.action();//通过有参构造方法创建对象
}
}
代码图如下
14.3 流处理
流处理有点类似与数据库语句 可以执行非常复杂的过滤 映射 和查找 手机功能,并且代码量很少 但是唯一的确定时代码可读性不高,如果开发者基础不好可能看不懂 流API所表达的含义
创建员工表封装成一个集合 里面有 名字 年龄 薪资 性别 部门 代码如下:
package 第十四章;
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name ;
private int age ;
private double salsary;
private String sex ;
private String dept;
//构造方法
public Employee(String name, int age, double salsary, String sex, String dept) {
super();
this.name = name;
this.age = age;
this.salsary = salsary;
this.sex = sex;
this.dept = dept;
}
@Override
//重写toString方法 方便打印员工信息
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", salsary=" + salsary + ", sex=" + sex + ", dept=" + dept
+ "]";
}
//以下是员工的属性的getter方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getSalsary() {
return salsary;
}
public String getSex() {
return sex;
}
public String getDept() {
return dept;
}
static List<Employee> getEmpList(){
List<Employee> list = new ArrayList<Employee>();
list.add(new Employee("喜羊羊",18,9000,"男","运营部"));//向列表中添加数据
list.add(new Employee("美羊羊",15,3000,"女","设计部"));
list.add(new Employee("废羊羊",22,9000,"男","开发部"));
list.add(new Employee("灰太狼",33,14000,"男","销售部"));
list.add(new Employee("红太狼",28,8000,"女","人事部"));
list.add(new Employee("懒洋洋",17,10300,"女","运营部"));
return list;//返回list集合
}
}
14.3.2 Optional类
Optional类像是一个容器,可以保存任何对象,并且针对NullPointerException空指针异常做了优化,保证Optional类保存的值不会null。因此Optional类是针对“对象可能是针对null也可能不是null”
的场景为开发者提供了优质的解决方案,减少了繁琐的异常处理
Optional类是final修饰的,所以不能有子类 Optional类是带有反省的类,所以该类可以保存任何对象的值
从Optional类的声明代码中就可以看出这种特性,JDK中的部分代码如下
public final class Optional<T>{
private final Tvalue;
...//省略其中代码
}
Optional类中有一个叫做value的成员属性 这个属性就是用来保存具体值的 value 是用反省T修饰的,并且还用了final修饰,这表示一个Optional对象只能保存一个值
Optional类提供了很多的封装,校验,和获取值的方法 如下
方法 返回类型 功能描述
empty() Optional<T> 静态方法。返回一个表示空值的Optional实例
filter() Optional<T> 如果Optional实例的value是有值,并且该值与给定的条件匹配,则返回这个值的Optional实例,否则返回一个表示空值的Optional石磊
get() T 如果Optional实例的value有值,则返回值否则抛出NoSuchElementException
of<T value> Optional<T> 敬爱方法。返回一个value值等于参数值Optional实例
ofNullabel<T value> Optional<T>
返回一个value值等于参数值的非null的Optional实例
orElse(T other)
T 如果Optional实例的value是优质的,则返回value的值,否则返回参数值
Collectors类
Collectors类为收集器类,该类实现了java.util.Collectors接口,可以将Stream流对象进行各种各样的封装,归集,分组等操作,同时,Collectors类还是提供了很多使用的数据加工方法,如数据统计计算等。Collectors类常用方法如下
方法 功能描述
averagingDouble(ToDoubleFunction<?super T>mapper) 计算流元素平均值
averagingInt(ToIntFunction<?super T >mapper) 计算流元素平均值
averagingLong(ToLongFunction<? super T> mapper) 计算流元素平均值
countiong() 统计元素个数
maxBy(Comparator<?super T>comparator) 返回符合条件的最大元素
minBy(Comparator<? super T >comparator) 返回符合条件的最小元素
summarizingInt(ToIntFunction<?super T>mapper) 返回流的元素的和
joining() 按照顺序将元素连接成一个String类型的数据
joining(CharSequence delimiter) 按照顺序将元素连接成一个String类型数据,并只当元素之间的分隔符
toList() 江流中的元素封装成List集合
toMap(Function<? superT,?extends K> ketMapper, Function <?super T,?extends U>value Mpper)
将流中的元素封装成Map集合
toSet() 将流中的元素封装成Set集合
groupingBy(Function<? super T,extends K> classifier) 根据分类函数对元素进行分组,并将结果封装成一个Mao集合
groupinBy(Function <? super ,?extends K>classifier,Collector<? super T A ,D>downstream) 根据分类函数对元素进行分组,并将结果封装成一个Map集合。第一个参数为一级分组条件,第二个参数为二级分组条件
数据查找
数据查找并不是在六种获取的数据(这属于数据过滤)而是判断流中释放符号条件数据,查找的结果时一个boolean值或者一个Optional类对象
1.allMatch()方法
allMatch()方法Stream接口提供的方法,该方法会判断流中的元素是否全部符合某一条件,返回结果是boolean值。如果所有都符合条件则返回true ,否则返回false。 代码如下:
package 第十四章;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
List <Employee> list = Employee.getEmpList();//获取所有员工信息
Stream<Employee> stream = list.stream();//转换为流
//筛选奶奶里大于30岁的员工
stream = stream.filter(emp -> emp.getAge()>30);//拿去指定条件 输出满足条件的数据 最终为了stream类型(流) filter返回一个满足条件的流
//stream= stream.limit(2);//限制输出的指定条数
List <Employee>result=stream.collect(Collectors.toList());//使用语句让其stream类型转换为List类型 使用toList方法
for (Employee i:result) {
System.out.print(i);
}
}
}