14.1lambda表达式
lambda表达式可以用非常少的代码实现抽象方法。不能独立执行,必须是实现函数式接口,并返回一个函数式接口的对象。
()->结果表达式
参数->结果表达式
(参数1,参数2,...,参数n)->结果表达式
package fourteen;
interface SayhHi{
String say();//抽象方法接口
}
public class NoParamDemo {
public static void main(String[] args) {
//无参数
//利用匿名内部类补全方法体
SayhHi sh1 = new SayhHi() {
public String say() {
return "这是匿名内部类";
}
};
System.out.print(sh1.say());
}
}
使用表达式表达
System.out.print(sh1.say());
//利用lambda表达式补全方法体
SayhHi sh2 =() -> {
return "这是lambda表达式";
};
System.out.println(sh2.say());
}
}
有参数
使用表达式
package fourteen;
interface AddInt{
int add(int a,int b);//抽象方法接口
}
public class Prama {
public static void main(String[] args) {
//有参数
//利用匿名内部类补全方法体
AddInt ai1 = new AddInt() {
public int add(int a,int b){
return a+b;
}
};
System.out.println("匿名内部类:" + ai1.add(3, 5));
//利用lambda表达式补全方法体
AddInt ai2=( a, b) -> {
return a+b ;
};
System.out.println("lambda表达式:"+ai2.add(3, 5));
}
}
例题
package fourteen;
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-89
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)); // 输出查询结果
}
}
//使用方法的引用补全方法体
双冒号::
static int add(int x, int y) {//方法的引用,这是方法体的方法
return x+y;
}
static int add(int x, int y) {//方法的引用,这是方法体的方法
return x+y;
}
完整代码
package fourteen;
interface AddInt{
int add(int a,int b);//抽象方法接口
}
public class Prama {
static int add(int x, int y) {//方法的引用,这是方法体的方法
//对象也可以找到这个方法体,非静态
return x+y;
}
public static void main(String[] args) {
//有参数
//利用匿名内部类补全方法体
AddInt ai1 = new AddInt() {
public int add(int a,int b){
return a+b;
}
};
System.out.println("匿名内部类:" + ai1.add(3, 5));
//利用lambda表达式补全方法体
AddInt ai2=( a, b) -> {
return a+b ;
};
System.out.println("lambda表达式:"+ai2.add(3, 5));
//使用方法的引用补全方法体
AddInt ai3 = Prama::add;//找到类,找到方法体
System.out.println("方法体:"+ai3.add(3, 5));
}
}
例14.8
package fourteen;
import java.text.SimpleDateFormat;
import java.util.Date;
interface InstanceMethodInterface { // 创建测试接口
String method(Date date); // 带参数的抽象方法
}
public class InstanceMethodDemo {
public String format(Date date) { // 格式化方法
// 创建日期格式化对象,并指定日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date); // 返回格式化结果
}
public static void main(String[] args) {
// 创建类对象
InstanceMethodDemo demo = new InstanceMethodDemo();
// 引用类对象的方法
InstanceMethodInterface im = demo::format;
Date date = new Date(); // 创建日期对象
System.out.println("默认格式:" + date); // 输出日期对象默认格式
// 输出经过接口方法处理过的格式
System.out.println("接口输出的格式:" + im.method(date));
}
}//14.8
//调用构造器
package fourteen;
interface ConIn{
ConDemo action();//创建接口,正好是这个类的构造器类型,抽象方法
}
public class ConDemo {
//使用无参的构造方法补全方法体
public ConDemo() {//构造方法要写小括号
System.out.println("无参构造方法");//构造方法
}
public ConDemo(int a) {//构造方法要写小括号
System.out.println("有参构造方法");//构造方法
}
public static void main(String args[]) {
ConIn ci1 = ConDemo:: new;//new一个对象
ci1.action();//调用action方法
//使用有参数的方法来补全方法体
//ConDemo action(int a);
//ConIn ci1 = ConDemo:: new;//new一个对象
//ci1.action(5);//调用action方法
}
}
stream接口
package fourteen;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) {
List list=Employee.getEmpList();//从employee表拿到list表中的员工表
Stream stream = list.stream();//调用list方法将表转换成流
//筛选年龄>30岁的员工
stream=stream.filter(sx-> sx.getAge()>30);//写条件,sx属于临时变量
//限制条数
stream = stream.limit(2);
List result = stream.collect(Collectors.toList());//转成List链表
for (Employee sx : result) {//for循环输出结果
System.out.println(sx);
}
}
}
数据分组
package fourteen;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class GroupDemo {
public static void main(String[] args) {
// 分组
List list=Employee.getEmpList();//从employee表拿到list表中的员工表
Stream stream = list.stream();//调用list方法将表转换成员工流
Map> map = //创建map集合存入,String代指dept,list链表指代map集合的value
stream.collect(Collectors.groupingBy(Employee::getDept));//利用流调用collect方法,分组方法,传入方法
Set depts = map.keySet();//获取map集合中的部门表
for(String dept:depts){//for循环一个部门,depts代指部门
System.out.println(dept+"员工信息如下:");//输出信息
List temp = map.get(dept);//分组列表输出
for(Employee g : temp){//temp是临时变量
System.out.println(g);//
}
System.out.println();
}
}
}
14.3流处理
流处理有点类似数据库的SQL语句,可以执行非常复杂的过滤、映射、查找和收集功能,并且代码量很少。唯一的缺点是代码可读性不高,如果开发者基础不好,可能会看不懂流API所表达的含义。
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;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", salary=" + salary + ", sex=" + sex + ", dept=" + dept
+ "]";
}
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 ListgetEmpList(){
List list=new ArrayList();
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,3000,"男","开发部"));
list.add(new Employee("老王",35,6000,"女","人事部"));
list.add(new Employee("小王",21,3000,"女","人事部"));
return list;
}
}
14.3.1stream接口简介
流处理的接口都定义在 java.uil.stream 包下。BaseStream接口是最基础的接口,但最常用的是BaseStream 接口的一个子接口——Stream 接口,基本上绝大多数的流处理都是在Stream接口上实现的。Stream 接口是泛型接口,所以流中操作的元素可以是任何类的对象。
Collection 接口新增两个可以获取流对象的方法。第一个方法最常用,可以获取集合的顺序流,方法如下:
Stream stream();
第二个方法可以获取集合的并行流,方法如下:
Stream parallelstream();
因为所有集合类都是Collection 接口的子类,如ArrayList类、HashSet类等,所以这些类都可以进行流处理。
List list = new ArrayList();
//创建集合
Stream s = list.stream();
//获取集合流对象
14.3.2 optional类
Optional 类像是一个容器,可以保存任何对象,并且针对 NullPointerException 空指针异常做了代化,保证Optional类保存的值不会是null。因此,Optional类是针对“对象可能是null也可能不是m的场景为开发者提供了优质的解决方案,减少了烦琐的异常处理。
Optional 类是用 final修饰的,所以不能有子类。Optional类是带有泛型的类,所以该类可以保存任何对象的值。
从Optional类的声明代码中就可以看出这些特性,JDK中的部分代码如下:
public final class Optional{
private final T value;
…}
//省略其他代码
列14.15
import java.util.Optional;
public class OptionalDemo{
public static void main(String[] args) {
Optional strValue = Optional.of("Hello");//创建有值对象
boolean haveValueFlag = strValue.isPresent();//判断对象中的值是不是空的
System.out.println("strValue 对象是否有值:"+ haveValueFlag);
if (haveValueFlag){ //如果不是空的
String str = strValue.get();//获取对象中的值
System.out.println("strValue 对象的值是:"+ str);
}
Optional noValue = Optional.empty();//创建空值对象
boolean noValueFlag = noValue.isPresent();//判断对象中的值是不是空的
System.out.println("noValue 对象是否有值:"+noValueFlag);
if (noValueFlag){//如果不是空的
String str = noValue.get();//获取对象中的值
System.out.println("noValue 对象的值是:"+str);
}else{//如果是空的
String str = noValue.orElse("使用默认值");//使用默认值
System.out.println("noValue 对象的值是:"+ str);
}}}
14.3.3collectors类
Collectors 类为收集器类,该类实现了java.util.Collector 接口,可以将Stream流对象进行各种各样的封装、归集、分组等操作。同时,Collectors 类还提供了很多实用的数据加工方法,
14.3.4数据过滤
数据过滤就是在杂乱的数据中筛选出需要的数据,类似SQL语句中的WHERE关键字,给出一定的条件,将符合条件的数据过滤并展示出来。
1.filter()方法
filter()方法是Stream 接口提供的过滤方法。该方法可以将lambda表达式作为参数,然后按照lambda表达式的逻辑过滤流中的元素。过滤出想要的流元素后,还需使用Stream 提供的collect()方法按照指定方法重新封装。
14.16
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util. stream.Stream;
public class FilterOddDemo{
static void printeach(String message, List list){//输出集合元素
System.out.print(message);//输出文字信息
list.stream().forEach(n->{//使用foeEach方法遍历集合并打印元素
System.out.print(n +"");
});
System.out.println(); //换行
}
public static void main(String[]args) {
List list = new ArrayList<>();//创建空数组
for (int i= 1;i<= 10;i++){//从1循环到10
list.add(i);//给集合赋值
}
printeach("集合原有元素:",list);//输出集合元素
Stream stream = list.stream();//获取集合流对象
//将集合中的所有奇数过滤出来,把过滤结果重新赋值给流对象
//使用forEach方法遍历集合并打印元素
stream = stream.filter(n -> n % 2 == 1);
//将流对象重新封装成一个List集合
List result = stream.collect(Collectors.toList());
printeach("过滤之后的集合元素:",result);//输出集合元素
}
}
14.17
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FilerDemo {
public static void main(String[]args){
List list = Employee.getEmpList();//获取公共类的测试数据
Stream stream = list.stream();//获取集合流对象
stream = stream.filter(people -> people.getAge()> 30);//将年龄大于30岁的员工过滤出来
List result = stream.collect(Collectors.toList());//将流对象重新封装成一个 List 集合
for (Employee emp : result){//遍历结果集
System.out.println(emp);//输出员工对象信息
}
}
}
2. distinct()方法
distinct()方法是Stream 接口提供的过滤方法。该方法可以去除流中的重复元素,效果与SOL中的DISTINCT关键字一样。
14.18
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util. stream.Stream;
public class DistinctDemo{
static void printeach(String message, List list) {//输出集合元素
System.out.print(message); //输出文字信息
list.stream().forEach(n->{//使用forEach方法遍历集合并打印元素
System.out.print(n +"");
});
System.out.println();//换行
}
public static void main(String[]args){
List list = new ArrayList();//创建集合
list.add(1);//添加元素
list.add(2);
list.add(2);
list.add(3);
list.add(3);
printeach("去重前:",list);//打印集合元素
Stream stream = list.stream();//获取集合流对象
stream = stream.distinct();//取出流中的重复元素
List reslut = stream.collect(Collectors.toList());//将流对象重新封装成一个List集合
printeach("去重后:",reslut);//打印集合元素
}
}
3. limit()方法
limit()方法是Stream 接口提供的方法,该方法可以获取流中前N个元素
14.19
import java.util.List;
import java.util. stream.Collectors;
import java.util. stream.Stream;
public class LimitDemo{
public static void main(String[]args) {
List list = Employee.getEmpList();//获取公共类的测试数据
Stream stream = list.stream();//获取集合流对象
stream = stream.filter(people ->"女".equals(people.getSex()));//将所有女员工过滤出来
stream = stream.limit(2);//取出前两位
List result = stream.collect(Collectors.toList());//将流对象重新封装成一个 List 集合
for (Employee emp : result) {//遍历结果集
System.out.println(emp); //输出员工对象信息
}
}
}
4.skip()方法
skip0方法是Stream接口提供的方法,该方法可以忽略流中的前N个元素。
14.20
import java.util.List;
import java.util. stream.Collectors;
import java.util. stream.Stream;
public class SkipDemo{
public static void main(String[]args) {
List list = Employee.getEmpList();//获取公共类的测试数据
Stream stream = list.stream();//获取集合流对象
stream = stream.filter(people ->"男".equals(people.getSex()));//将所有男员工过滤出来
stream = stream.skip(2);//跳过前两位
List result = stream.collect(Collectors.toList());//将流对象重新封装成一个List集合
for (Employee emp : result){
System.out.println(emp);
}
}
}
14.3.5 数据映射
数据的映射和过滤概念不同:过滤是在流中找到符合条件的元素,映射是在流中获得具体的数强.Stream 接口提供了map()方法用来实现数据映射,map()方法会按照参数中的函数逻辑获取新的对象,新的流对象中元素类型可能与旧流对象元素类型不相同。