1.Lambda表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
lambda表达式语法格式:
(参数列表)->{重写方法体}
//格式一
(parameters) -> expression
//格式二
(parameters) ->{ statements; }
lambda表达式用法:
实现接口重写抽象方法,当接口中只有一个抽象方法时才能使用该表达式。
举例如下:
定义计算器接口,完成接口方法的调用
public class Demo {
public static void main(String[] args) {
//1.调用接口中的实体方法cj(int x,int y)(静态方法)
//通过接口名.静态方法 完成调用
System.out.println(Calc.cj(1,5));
//2.调用接口里的实体方法(默认方法)
//匿名内部类的对象调用接口里的实体方法
System.out.println(new Calc() {
@Override
public int max(int x, int y) {
return 0;
}
}.sum(2,3));
//3.jdk 1.8支持 lambda表达式--实现接口重写抽象方法,接口中只有一个抽象方法才能
使用该表达式
//语法格式:(参数列表)->{重写方法体}
Calc c = (int x,int y)->{return x>y?x:y;};
System.out.println("c"+c.max(1,2));
//可以省略参数类型不写,重写参数列表被保证
Calc c1 = (x,y)->{return x>y?x:y;};
System.out.println("c1"+c1.max(1,2));
//当重写的方法体只有一句话时,可以省略return以及大括号
Calc c2 = (x,y)->x>y?x:y;
System.out.println("c2"+c2.max(1,2));
}
}
interface Calc{
//求2个数的最大值
//抽象方法
int max(int x,int y);
//求和--实体化方法
//1.8 后default 只能在接口中修饰实体方法(默认方法)
//其他地方无法使用,修饰符 不写就是默认,但是不能加 default
public default int sum(int x,int y){
return x+y;
}
//求乘积--实体方法(静态方法)--使用更接近抽象类
public static int cj(int x,int y){
return x*y;
}
}
运行结果:
2.函数式接口
函数式接口在java中是指:有且仅有一个抽象方法的接口,它是java1.8的新特性,函数式接口上添加注解@FunctionalInterface。
函数式接口,即适用于函数式编程场景的接口。而java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
注:“语法糖"是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的“语法糖”,但是二者在原理上是不同的。
函数式接口@FunctionalInterface 的特点:
- 该注解只能标记在"有且仅有一个抽象方法"的接口上。
- JDK8接口中的静态方法和默认方法,都不算是抽象方法。
- 接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。
- 该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
接口源码:
注意:Java8新引入函数式编程,函数式编程不属于面向对象。函数式接口,它指的是有且只有一个未实现的方法的接口,一般通过FunctionalInterface这个注解来表明某个接口是一个函数式接口。函数式接口是Java支持函数式编程的基础。
对于上面计算器Calc的例子,Calc就是一个函数式接口,加上@FunctionalInterface注解,不会出现错误,运行正常
public class Demo {
public static void main(String[] args) {
//1.调用接口中的实体方法cj(int x,int y)(静态方法)
//通过接口名.静态方法 完成调用
System.out.println(Calc.cj(1,5));
//2.调用接口里的实体方法(默认方法)
//匿名内部类的对象调用接口里的实体方法
System.out.println(new Calc() {
@Override
public int max(int x, int y) {
return 0;
}
}.sum(2,3));
//3.jdk 1.8支持 lambda表达式--实现接口重写抽象方法,接口中只有一个抽象方法才能使用该表达式
//语法格式:(参数列表)->{重写方法体}
Calc c = (int x,int y)->{return x>y?x:y;};
System.out.println("c:"+c.max(1,2));
//可以省略参数类型不写,重写参数列表被保证
Calc c1 = (x,y)->{return x>y?x:y;};
System.out.println("c1:"+c1.max(1,2));
//当重写的方法体只有一句话时,可以省略return以及大括号
Calc c2 = (x,y)->x>y?x:y;
System.out.println("c2:"+c2.max(1,2));
}
}
//定义计算器接口
//函数式接口--@FunctionalInterface--直接使用lambda表达式
//函数式编程--不属于面向对象
@FunctionalInterface
interface Calc{
//求2个数的最大值
//抽象方法
int max(int x,int y);
//求和--实体化方法
//1.8 后default 只能在接口中修饰实体方法(默认方法)
//其他地方无法使用,修饰符 不写就是默认,但是不能加 default
public default int sum(int x,int y){
return x+y;
}
//求乘积--实体方法(静态方法)--使用更接近抽象类
public static int cj(int x,int y){
return x*y;
}
}
运行结果:
3.函数式接口和Lambda表达式的用法举例
示例一:
public class LambdaDemo {
public static void main(String[] args) {
int[] arr = {1,8,7,5};
//Lambda 表达式 arr1 不能与上面的arr 重名
//Arraysort a = (int[] arr1)-> Arrays.sort(arr1);
//写法二
//参数类型和重写方法体的大括号可以省略
//Arraysort a = (arr1)->Arrays.sort(arr1);
//当参数只有一个时小括号可以省略
//Arraysort a = arr1->Arrays.sort(arr1);
// :: 代表传递静态方法
Arraysort a = Arrays::sort;
//给数组排序
a.sortArray(arr);
//测试
System.out.println(Arrays.toString(arr));
}
}
//函数式接口
interface Arraysort{
//给数组排序
void sortArray(int[] arr);
}
示例二:
public class LambdaDemo2 {
public static void main(String[] args) {
//
List<String> list = new ArrayList<>();
//添加元素
list.add("b");
list.add("a");
list.add("c");
list.add("d");
list.add("e");
//Comparator --比较器
//Comparator 是函数式接口--@FunctionalInterface--直接使用lambda表达式
/* list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.charAt(0)-o2.charAt(0);
}
});*/
list.sort(((o1, o2) -> o1.charAt(0)-o2.charAt(0)));
//输出结果
System.out.println(list);
}
}
示例三:
public class LambdaDemo3 {
public static void main(String[] args) {
//创建代表文件类的对象
File file = new File("D:\\filetest");
//过滤获取的所有信息名称中是否含有数字
/* File[] fs = file.listFiles(new FileFilter() {
//指定过滤规则
@Override
public boolean accept(File pathname) {
//数量词--表示前面可以出现次数
//.代表任意字符
//正则语法匹配是否含有数字
return pathname.getName()
.matches(".*\\d.*");
}
});*/
//使用lambda 表达式
/* File[] fs = file.listFiles(pathname->pathname.getName()
.matches(".*\\d.*"));*/
/* File[] fs = file.listFiles(new FilenameFilter() {
//指定过滤规则
@Override
public boolean accept(File dir, String name) {
return name.matches(".*\\d.*");
}
});*/
//使用lambda 表达式
File[] fs = file.listFiles(((dir, name) -> name.matches(".*\\d.*")));
for (File f:fs
) {
System.out.println(f);
}
}
}