14.1.1lambda表达式简介
lambda表达式可以用非常少的代码实现抽象方法。lambda表达式不能独立执行,因此必须实现函数式接口,并且会返回一个函数式接口的对象。lambda表达式的语法非常特殊。
如下
()->结果表达式
参数->结果表达式
(参数1,参数2...参数n)->结果表达式
lambda表达式的语法非常抽象,并且有着非常强大的自动化功能,如自动识别泛型、自动数据类型转换等,
lambda表达式语法用如下方式理解:
() -> {代码块}
这个方法 按照 这样的代码来实现
误区警示
“->”符号是由 英文状态 下的“-”和“>”组成的,符号之间没有空格
14.1.2lambda表达式实现函数氏接口、
例题1
lambda表达式
package 十四;
interface sayhi{
String say();
}
public class NoParamDemo {
public static void main(String[] args) {
sayhi shi = new sayhi() {
public String say() {
return"这是匿名内部类";
}
};
System.out.println(shi.say());
}
}
package 十四;
interface sayhi{
String say();
}
public class NoParamDemo {
public static void main(String[] args) {
//使用匿名内部类补全方法体
sayhi shi = new sayhi() {
public String say() {
return"这是匿名内部类";
}
};
System.out.println(shi.say());
//使用lambda表达式补全方法体
sayhi sh2 = ()->{
return"lambda";
};
System.out.println(sh2.say());
}}
package 十四;
interface CheckGrade{
String check(int grade);//查询成绩结果
}
public class GradeDemo {
public static void main(String[] args) {
CheckGrade g =(n)->{ //lambda表达式实现代码块
if(n>=90&&n<=100) { //如果成绩在90~100
return "成绩为优"; //输出成绩为优
}else if(n>=80&&n<90) { //如果成绩在80~90
return "成绩为良"; //输出成绩为良
}else if(n>=60&&n<80) { //如果成绩在60~79
return"成绩为中"; //输出成绩为中
}else if (n>0&&n<60) { //如果成绩小于60
return "成绩为差"; //输出成绩为差
}else { //其他数字不是有效成绩
return"成绩无效"; //输出成绩无效
}
}; //不要丢掉lambda语句后的分号
System.out.println(g.check(89)); //输出查询结果
}
}
14.1.3lambda表达式调用外部变量
14.1.4lambda表达式与异常处理
14.2方法的引用
14.2.1引用静态方法
14.2.2引用成员方法
引用成员方法的语法如下:
对象名::成员方法名
与引用静态方法语法不同,这里操作符左侧的必须是一个对象名,而不是类名。
例题14.8
创建函数式接口和测试类,在接口中定义抽象方法method(),在测试类中编写一个可以用来实现抽象方法的成员方法——format()方法。在main()方法中创建接口对象,并使用引用成员方法的语法让接口对象的抽象方法按照测试类的format()方法来实现。
package 十四;
import java.text.SimpleDateFormat;
import java.util.Date;
interface MetodDemoInterface{ //创建测试接口
String method(Date date); //带参数的抽象方法
}
public class MethodDemo {
public String format(Date date) { //格式化方法
//创建日期格式化对象,并指定日期格式
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date); //返回格式化结果
}
public static void main(String[] args) {
MethodDemo demo =new MethodDemo(); //创建类对象
MetodDemoInterface im =demo::format; //引用类对象的方法
Date date =new Date(); //创建日期对象
System.out.println("默认格式:"+date); //输出日期对象默认格式
System.out.println("接口输出的格式"+im.method(date));//输出经过接口方法处理过的格式
}
}
结果
14.2.3引用带泛型的方法
14.2.4引用构造方法
引用无参构造方法
引用构造方法的语法如下:
类名::new
因为构造方法与类名相同,如果操作符左右都写类名,会让操作符误以为是在引用与类名相同的静态方法,这样会导致程序出现BUG,所有引用构造方法的语法使用了new关键字。操作符右侧的写new关键字,表示引用构造方法。
例题14.10
package 十四;
interface ConIn{ //构造方法接口
ConDemo action(int i);//调用无参方法
}
public class ConDemo { //测试类
public ConDemo() { //无参构造方法
System.out.println("无参构造方法");
}
public ConDemo(int i) { //有参构造方法
System.out.println("有参构造方法"+i);
}
public static void main(String[] args) {
ConIn ci1 = ConDemo::new;//引用ConIn类的构造方法
ConDemo b=ci1.action(5);//通过无参方法船舰对象
}
}
结果
14.3流处理
流处理有点类似数据库的SQL语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一缺点是代码可读性不高,如果开发者基础不好,可能会看不懂API所表达的含义。
例题14
package 十四;
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private int age;
private double salary;
private String sex;
private String dept;
public Employee(String name, int age, double salary, String sex, String dept) {
super();
this.name = name;
this.age = age;
this.salary = salary;
this.sex = sex;
this.dept = dept;
}
//重写toString()方法,方便打印员工信息
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + ", sex=" + sex + ", dept=" + dept
+ "]";
}
//以下是员工属性的getter方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getSalary() {
return salary;
}
public String getSex() {
return sex;
}
public String getDept() {
return dept;
}
static List<Employee> getEmpList(){ //提供数据初始化方法
List<Employee> list = new ArrayList<Employee>(); //添加员工数据
list.add(new Employee("莱斯特",40,9000,"男","运营部"));
list.add(new Employee("佩奇哈里斯",24,5000,"女","开发部"));
list.add(new Employee("富兰克林",32,7500,"男","销售部"));
list.add(new Employee("翠花",28,5500,"女","销售部"));
list.add(new Employee("查理",21,6000,"男","开发部"));
list.add(new Employee("老王",35,6000,"女","人事部"));
list.add(new Employee("小王",21,3000,"女","人事部"));
return list;
}}
14.3.1stream接口简介
流处理的接口都定义在Java.util.stream包下。
14.3.3Collectors类
Collectors类为收集器类,该类实现了Java.util.Collector接口,可以将stream流对象进行各种各样的封装、归集、分组等操作。
14.3.4数据过滤
数据过滤就是在杂乱的数据中筛选出需要的数据,类似SQL语句中的WHERE关键字,给出一定的条件,将符合条件的数据过滤并展示出来。
例题17
package 十四;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
List<Employee> list = Employee.getEmpList();
Stream<Employee> stream = list.stream();
//筛选年龄大于30岁的员工
stream = stream.filter(a -> a.getAge()>30);
List<Employee> result = stream.collect(Collectors.toList());
for(Employee e : result) {
System.out.println(e);
}
}
}
//限制条数
stream = stream.limit(2);
14.3.5数据映射
数据的映射和过滤概念不同:过滤式在流中找到符合条件的元素,映射是在流中获得具体的数据。
14.3.6数据查找
本节所讲的数据查找并不是在流中获取数据(这属于数据过滤),而是判断流中是否符合条件的数据,查找的结果是一个boolean值或一个Optional类的对象。本节将讲解allMatch()、anyMatch()、noneMatch()和findFirst()这4个方法。
14.3.7数据收集
数据收集可以理解为高级的“数据过滤+数据映射”,是对数据的深加工。本节将讲解两种实用场景:数据统计和数据分组。
1数据统计
数据统计不仅可以筛选出特殊元素,还可以对元素的属性进行统计计算。这种复杂的统计操作不是由Stream实现的,而是由Collectors收集器实现的,收集器提供了非常丰富的API,有着强大的数据挖掘能力。