day26—JDK8新特性
- Lambda表达式
- Lambda表达式的作用 : 主要就是简化匿名内部类对象的实现过程
匿名内部类 : 可以作为一个类的子类或者是一个接口的实现类存在 - Lambda表达式的实现方式
- 符号 : -> , 叫做箭头运算符,也叫做Lambda运算符
- -> 的作用 : 将需要重写的方法分成两部分
-> 的左边部分,表示需要重写方法的参数列表
-> 的右边部分,表示需要重写的方法的实现过程(实现逻辑) - Lambda实现的语法格式:
-
需要重写的方法,没有参数,也没有返回值类型,并且实现语句只有一句
()->System.out.println(“打印”); -
需要重写的方法,有1个参数,没有返回值类型,并且实现语句只有一句
(x)->System.out.println(xx);
注意 : 如果Lambda表达式中的参数只有一个,那么小括号可以省略
x ->System.out.println(xx); -
需要重写的方法,多个参数,没有返回值类型
(x,y)->System.out.println(x*y);
(x,y)->{
可以写任意的逻辑语言
}
注意: 如果Lambda表达式重写的方法,方法内容有多句,将多条语句放到大括号中即可 -
需要重写的方法,多个参数,有返回值类型,并且实现语句多条
(x,y,z)->{
// 写方法的实现逻辑
return 数值;
}
注意: 如果lambda表达式的重写内容只有一句话,省略大括号
如果这一句话就是return的结果,那么return也一起省略掉
Lambda语法格式1代码
package com.zgjy.lambda;
public class LambdaDemo1 {
public static void main(String[] args) {
lambda1();
}
// 1. lambda表达式实现没有参数没有返回值类型的接口
public static void lambda1() {
// 1. 创建一个匿名内部类对象实现接口MyInter1
MyInter1 my = new MyInter1() {
@Override
public void fun() {
System.out.println("匿名内部类实现的接口MyInter1");
}
};
my.fun();
// 2. Lambda表达式实现接口MyInter1
// Lambda表达式可以实现的接口,接口中只能有一个抽象方法
// Lambda表达式替代简化了匿名内部类的实现过程
MyInter1 my1 = () -> System.out.println("Lambda表达式实现的接口MyInter1");
my1.fun();
}
}
// 定义一个接口
interface MyInter1{
// 定义一个抽象方法
// 没有返回值类型,没有参数
public abstract void fun();
}
Lambda语法格式2代码
package com.zgjy.lambda;
public class LambdaDemo2 {
public static void main(String[] args) {
// 1. 使用匿名内部类对象的方式实现接口MyInter2
MyInter2 my2 = new MyInter2() {
@Override
public void fun2(int x) {
System.out.println(x+x);
}
};
my2.fun2(5);// 10
// 2. 使用lambda表达式方式实现接口MyInter2
// 带有一个参数,没有返回值类型
MyInter2 my = (y)-> System.out.println(y*y);
my.fun2(10);//100
// Lambda表达式的参数列表只有一个,小括号可以省略
MyInter2 my1 = y -> System.out.println(y*y);
my.fun2(8);//64
}
}
interface MyInter2{
//定义一个带有一个参数,没有返回值类型的抽象方法
public abstract void fun2(int x);
}
Lambda语法结构3代码
package com.zgjy.lambda;
public class LambdaDemo3 {
public static void main(String[] args) {
// 1. 匿名内部类对象实现MyInter3接口
MyInter3 my= new MyInter3() {
@Override
public void fun3(int x, int y) {
int w = x +y;
System.out.println(w);
}
};
my.fun3(5, 10);// 15
// 2. Lambda表达式实现MyInter3接口
MyInter3 my1 = (x,z)->System.out.println(x*z);
my1.fun3(2, 6);// 12
// Lambda表达式的方法重写逻辑多条语句,使用大括号包裹
MyInter3 my2 = (w,y)->{
int q = w + y;
System.out.println(q*2);
};
my2.fun3(1, 2);// 6
}
}
interface MyInter3{
// 定义抽象方法,有多个参数,没有返回值类型
public abstract void fun3(int x , int y);
}
Lambda语法格式4代码
package com.zgjy.lambda;
public class LambdaDemo4 {
public static void main(String[] args) {
// 1. 匿名内部了对象实现接口MyInter4
MyInter4 my = new MyInter4() {
@Override
public int fun4(int x, int y, int z) {
// TODO Auto-generated method stub
return 0;
}
};
System.out.println(my.fun4(1, 2, 3));// 0
// 2. lambda表达式实现接口MyInter4
MyInter4 my1 = (x,y,z)->{
int w = x + y + z;
return w;
};
System.out.println(my1.fun4(1, 2, 3));// 6
// 如果lambda表达式的重写内容只有一句话,省略大括号
// 如果这一句话就是return的结果,那么return也一起省略掉
MyInter4 my2 = (x,y,z)->x+y+z;
System.out.println(my2.fun4(5, 10, 15));// 30
}
}
interface MyInter4{
//定义抽象方法,多个参数,带有返回值类型
public abstract int fun4(int x,int y,int z);
}
- 函数式接口
2.1 函数式接口的概念 - 什么叫做函数式接口?
定义一个接口,这个接口中只有一个抽象方法,那么这个接口称为函数式接口 - Lambda表示式,就是为了实现函数式接口
- 函数式接口的作用:
有些其他类的编程语言中,支持一种数据类型叫做函数,函数对应java中的方法,于是其他语言中函数可以作为参数传递,但是Java不行,因为java中的方法不是一种数据类型,不能单独存在,于是将这个函数(方法)封装到一个接口中,那么传递这个接口,就相当于在传递这个函数内容
方法表示的是一种实现过程,有一些的场景下,需要将实现过程作为一个参数传递,传递的是一种思想,二不是简单的数值 - 如何判断一个接口是函数式接口?
引入一个注解 @FunctionalInterface , 在定义的接口之上使用注解,如果接口不报错,证明是一个函数式接口,报错,证明不是函数式接口
2.2 常用的内置函数式接口
-
Consumer : 消费型接口
方法 : accept(T t) : 就是将给出的参数t进行消费,Java中的消费就是指使用,可以任意的使用这个变量t,不需要返回值类型 -
Supplier : 供给型接口
方法 : T get() : 不需要参数,直接给出一个结果 -
Function<T,R> : 函数式接口
方法 : R apply(T t) : 提供参数类型t,返回结果类型R -
Predicate : 断言型接口
方法 : boolean test(T t) : 提供一个数据t,将t是否符合规则结果输出
2.3消费型接口
Consumer : 消费型接口
方法 : accept(T t) : 就是将给出的参数t进行消费,Java中的消费就是指使用,可以任意的使用这个变量t,不需要返回值类型
代码
package com.zgjy.interfaceDemo;
import java.util.function.Consumer;
// 消费型接口的使用案例
public class ConsumerDemo {
public static void main(String[] args) {
// get方法需要3个参数
// 1. money : 钱数
// 2. Consumer<String> con--->函数式的接口
// 接口作为参数传递,实际应该传递的是接口的实现类
Consumer<String> con = (t)->System.out.println("买了"+t);
get(800,con,"大宝剑");
get(800,con,"小兔兔");
}
// Consumer<String> con : 一个消费型的接口,作用就是能对一个String类型的数据
// 进行消费
public static void get(int money,Consumer<String> con,String str) {
System.out.print("今天花了"+money);
con.accept(str);
}
}
2.4供给型接口
Supplier : 供给型接口
方法 : T get() : 不需要参数,直接给出一个结果
需求: 创建一个集合ArrayList ,集合中存储的元素个数,由参数决定,集合中存储的整数内容不确定(先设计为30-80之间的随机整数),定义方法,返回这个集合
代码
package com.zgjy.interfaceDemo;
import java.util.ArrayList;
import java.util.Random;
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
// 需要一个Supplier sup的实现类
// 30-80之间的随机整数
Supplier sup = ()->new Random().nextInt(51)+30;
Supplier<Integer> sup1 = new Supplier<Integer>() {
@Override
public Integer get() {
// TODO Auto-generated method stub
return new Random().nextInt(51)+30;
}
};
ArrayList<Integer> list = getArr(3,sup1);
System.out.println(list);
}
public static ArrayList<Integer> getArr(int n,Supplier<Integer> sup){
ArrayList<Integer> list = new ArrayList<>();
for(int i = 0 ; i < n ; i++) {
list.add(sup.get());
}
return list;
}
}
2.5函数型接口
Function<T,R> : 函数式接口
方法 : R apply(T t) : 提供参数类型t,返回结果类型R
要求: 给你一个int类型参数,返回一个int类型数据,返回的数据,可能每次方法调用可能不一致
代码
package com.zgjy.interfaceDemo;
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
// 匿名内部类对象实现Function<Integer,Integer> fun函数式接口
Function<Integer,Integer> fun = new Function<Integer,Integer>(){
@Override
public Integer apply(Integer t) {
// TODO Auto-generated method stub
return t*2;
}
};
int result = get(5,fun);
System.out.println(result);// 10
// 使用lambda表达式实现Function<Integer,Integer> fun函数式接口
Function<Integer,Integer> fun1 = x -> {
x = x * 2 ;
return x +3;
};
int result1 = get(5,fun1);
System.out.println(result1);// 13
}
// R apply(T t)
public static int get(int x , Function<Integer,Integer> fun) {
return fun.apply(x);
}
}
2.6断言型接口
Predicate : 断言型接口,一般用于做数据的筛选
方法 : boolean test(T t) : 提供一个数据t,将t是否符合规则结果输出
要求: 创建一个集合ArrayList,向集合中添加数据,方法功能 : 将集合中符合某种规则的数据筛选到新的集合中,返回新的集合
代码
package com.zgjy.interfaceDemo;
import java.util.ArrayList;
import java.util.function.Predicate;
public class PerdictedDemo {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
// 匿名对象实现Predicate<Integer> pre
Predicate<Integer> pre = new Predicate<Integer>() {
@Override
public boolean test(Integer t) {// 可以被2整除的数据
if(t % 2 == 0) {
return true;
}else{
return false;
}
}
};
ArrayList<Integer> list1 = returnArr(list,pre);
System.out.println(list1);
// Lambda表达式进行数据筛选
// 可以被3整除的
Predicate<Integer> pre1 = x -> x % 3 == 0 ;
Predicate<Integer> pre2 = x -> {
if(x % 4 == 0) {
return true;
}else{
return false;
}
};
// 筛选被3整除的数据
ArrayList<Integer> list2 = returnArr(list,pre1);
System.out.println(list2);
// 筛选被4整除的数据
ArrayList<Integer> list3 = returnArr(list,pre2);
System.out.println(list3);
}
/*
* 要求: 创建一个集合ArrayList<Integer>,向集合中添加数据
* 方法功能 : 将集合中符合某种规则的数据筛选到新的集合中,返回新的集合
*
* */
// Predicate pre 参数 : 传递的实际上是对于一个Integer类型参数的判断方式
public static ArrayList returnArr(ArrayList arr, Predicate pre){
ArrayList list = new ArrayList<>();
// 将集合中的每一个元素获取到,验证每一个元素是否符合规则
// 符合 : 添加到新的集合中
// 不符合 : 不添加,继续进行下一个元素的验证
for(Integer i : arr) {
if(pre.test(i)) {// 符合
list.add(i);
}
}
return list;
}
}
- Streaming表达式
Stream接口 : 是一个流资源,主要功能是能进行数据的筛选和遍历
Stream中的比较常用的方法: - filter(Predicate<? super T> predicate) : 功能是能按照参数的断言型接口进行数据的筛选,返回值类型Stream的实现类
参数 : 是一个断言型的接口,方法实际调用需要传递接口的实现类(可以使用Lambda表达式) - forEach(Consumer<? super T> action) : 功能进行数据的遍历
参数 : 是一个消费型的接口,参数的作用,消费(操作给出的数据),循环操作
注意 : 因为Collection单列集合的顶层父接口,从JDK1.8版本开始,添加了一个方法,
stream() : 能获取到一个Stream的实现类对象,返回值类型Stream类型
要求 : 创建一个集合ArrayList , 集合中存储的是姓名, 将姓张的,并且名字带有3个字的数据输出出来
代码
package com.zgjy.stream;
import java.util.ArrayList;
public class StreamDemo {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add(“张三丰”);
list.add(“李24”);
list.add(“张三”);
list.add(“张无忌”);
list.add(“张二麻子”);
list.add(“周芷若”);
getName(list);
System.out.println("---------");
streamGetName(list);
}
/*
* 要求 : 创建一个集合ArrayList<String> ,
* 集合中存储的是姓名, 将姓张的,并且名字带有3个字的数据输出出来
* */
// 1. 使用以前学习的方法
public static void getName(ArrayList<String> list) {
// 1. 获取到集合中的每一个元素
for( String name : list) {
// 2. 判断名字是否符合规则
// 1) 姓张: 名字字符串的第一个字符是张字
// 2) 名字长度3个字 : 名字的字符串长度为3
if(name.startsWith("张") && name.length() == 3) {
System.out.println(name);
}
}
}
// 2. 使用Stream进行数据的筛选和遍历
public static void streamGetName(ArrayList<String> list) {
// 1. 获取到一个Stream的实现类
// 1) list.stream() ---> 获取到Stream的一个实现类对象
// 2) 链式调用filter(predicate)---> 使用断言型接口的实现方式
// boolean test(T t)
// 3) 将符合条件的数据循环的输出,使用Stream中的forEach
// forEach(Consumer)
// apply(T t)
list.stream().filter(x->x.startsWith("张"))
.filter(x->x.length()==3).forEach(x->System.out.println(x));
}
}