目录
一、Lambda表达式是什么?什么场景下使用Lambda?
1.Lambda 表达式是什么
2.函数式接口是什么
第二章、怎么用Lambda
1.必须有一个函数式接口
2.省略规则
3.Lambda经常用来和匿名内部类比较
第三章、具体使用举例()
1.案例一,自己写简单Lambda表达式(自定义的函数式接口)
2.案例二,Lambda表达式创建线程(Runnable函数式接口)
3.案例三,Lambda表达式写判断型接口(Predicate函数式接口)
4.案例四,Lambda表达式写比较器(Comparator函数式接口)
5.案例五,Lambda表达式写过滤器(FileFilter函数式接口)
一、Lambda表达式是什么?什么场景下使用Lambda?
1.Lambda 表达式是什么
1.Lambda 表达式本质上是一个匿名方法,是JAVA8中提供的一种新的特性(一种新的表达方式,以前旧的写法换成新的写法,可以写出更简洁、更灵活的代码)。
我们以前定义一个方法总是想到方法的五要素:
修饰符 返回值类型 方法名(参数列){方法体}
2.我要打印一段话,用Lambda翻新成一个匿名方法,语法格式如下:
以前写个方法:
public void prin(){
System.out.println(" 打印这个Lambda啊");
}
现在用Lambda写:
最简单的三要素:
参数列表 操作符箭头 方法体
() -> {System.out.println(" 打印这个Lambda啊");}
注意:直接把下面这段拿去运行是不行的,忍住先往下看:
() -> { System.out.println(" 打印这个Lambda啊");}
在这个基础上我们进行拓展丰富,在参数列表里放一个参数。
注意:这个也不能运行
有一个参数,并且无返回值;
参数列表里放个参数a 操作符箭头 方法体
(参数a) -> System.out.println(a);
继续丰富,在参数列表里放两个参数,有返回值。
注意1:前面多了个Comparator com =
注意2:可以复制运行了。因为这段代码前面多了一个Comparator com =,这Comparator是个接口,而且是函数式接口,那么函数式接口是什么。
//有两个以上的参数,有返回值,并且大括号方法体里头多条语句
Comparator com = (a, b) -> {
System.out.println("打印一下"); return Integer.compare(10, 11);
};
2.函数式接口是什么
接口好理解,那什么是函数式接口呢?函数式接口是有且仅有一个抽象方法(不包含object中的方法)的接口。注意:我们只需要关注抽象方法的个数,不用关注其他类型的方法个数。
如图:我们可以用注解@FunctionalInterface 检测是否为函数式接口
第二章、怎么用Lambda
1.必须有一个函数式接口
看了第一章我们知道,Lambda表达式前面放普通接口是不行的,必须是Comparator 这种函数式接口。如图Collection接口不是函数式接口,报错了:
把Collection接口换成函数式接口Consumer 就可以复制运行了。
//Consumer 是函数式接口
Consumer con = (x) -> System. out .println(x);
con.accept( "这个可以运行打印了" );
2.省略规则
1. 参数类型必须同时省略
2. 一个参数时,参数的括号可省略
3. 代码块里只有一句时,可省略大括号,分号和return
Comparator com = (x, y) -> Integer.compare(10, 13);
3.Lambda经常用来和匿名内部类比较
但注意:
1.Lambda表达式虽然简洁,用()->就可以代替整个匿名内部类,但只能用于函数式接口(有仅只有一个抽象方法的接口)。匿名内部类却可以用于接口,抽象类或者普通类。举个函数式接口Runnable接口的例子:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是匿名内部类里传了个Runnable的实现类对象");
}
}).start();
用Lambda写一下
new Thread(() -> System.out.println("好家伙这么简洁")).start();
第三章、具体使用举例()
我们要明确方法体才是关键所在,Lambda表达式方法体里的方法来自哪个函数式接口,这个接口的抽象方法作用是什么,才能有明确的目的去写Lambda表达式,也就是我们说的:“解决什么问题”。
1.案例一,自己写简单Lambda表达式(自定义的函数式接口)
1.自己写一个函数式接口注意只能有一个抽象方法,
public interface Test {
//有且仅有一个抽象方法
public String TestFunc(String test_str);
}
2.Lambda表达式:把字符串传入箭头符号右边的方法体
Test test =(str)->{ System.out.println(str); return str;};
String str=test.TestFunc("打印这个字符串");
}
2.案例二,Lambda表达式创建线程(Runnable函数式接口)
明确作用和方法:
1.Runnable接口,Runnable
为非 Thread
子类的类提供了一种激活方式。把Runnable的实例传给Thread
实例并将自身作为运行目标,就可以运行实现 Runnable
的类而无需创建 Thread
的子类。
唯一的抽象方法run()
使用实现接口Runnable
的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的run
方法
// 匿名内部 类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("匿名对象 传递线程任务.....");
}
}).start();
2.再用Lambda表达式写
/*Lambda表达式 省略格式
1. 参数类型必须同时省略
2. 一个参数时,参数的括号可省略
3. 代码块里只有一句时,可省略大括号,分号和return */
new Thread(() -> System.out.println("Lambda表达式 启动线程...")).start();
3.案例三,Lambda表达式写判断型接口(Predicate函数式接口)
明确作用和方法:Predicate判断型接口,可以对数据进行条件的判断,返回判断的结果。
唯一抽象方法 boolean test(T t)
在给定的参数上进行条件评估。
演示:1.第一步先创建集合list
//先创建一个集合
ArrayList<Integer> list = new ArrayList<>();
//使用addAl方法添加元素
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9);
2.用list调用removeIf()方法,
方法介绍: default boolean removeIf(Predicate<? super E> filter) ,删除集合中满足给定条件的元素
注意:因为removeIf()参数列表里需要传递的是函数式接口Predicate实例
所以我们可以在方法的括号里头,用上匿名内部类写法;在大括号里重写这个唯一的抽象方法。
// 删除集合中的偶数 default boolean removeIf(Predicate<? super E> filter) 删除满足给定谓词的此集合的所有元素。
list.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer % 2 == 0;
}
});
System.out.println(list);
3.在前面我们提到Predicate接口是函数式接口,所以我们自然可以用Lambda重写一次
//不省略格式
list.removeIf( (Integer itgr) -> { return itgr % 2 == 0;});
//省略写法
// 1.一个参数把括号和参数类型 省略
// 2.只有一条方法语句把大括号{}和; return 省略
list.removeIf( itgr -> itgr % 2 == 0);
//打印集合
System.out.println(list);
4.案例四,Lambda表达式写比较器(Comparator函数式接口)
明确作用和方法:Comparator函数式接口,强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator实例 传递给 sort 方法(如 Collections.sort
或 Arrays.sort
),从而允许在排序顺序上实现精确控制。
唯一的抽象方法
compare(T o1, T o2)
比较用来排序的两个参数
演示:
1.创建集合加入元素
// 创建集合使用addAll()方法加入元素
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 3, 2, 4, 5, 7, 9, 8, 6);
// 先用sort(list)方法进行 升序 排序
Collections.sort(list);
System.out.println(list);
2.注意:因为参数列表里需要传递的参数类型是函数式接口Comparator
所以我们可以在sort()方法的括号里头,用上匿名内部类写法;在里头重写这个唯一的抽象方法compare()
//匿名内部类 写降序排序,Collections.sort(List<T> list, Comparator<? super T> c)
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
3.用Lambda重写一下
//lambda表达式写 降序排序
// Collections.sort(list,(Integer o1, Integer o2)->{ return o2 - o1;});
// 简化格式,两个参数类型一样省略参数类型但是括号不能省略,方法体只一条语句省略{};return
Collections.sort(list,(o1,o2)-> o2 - o1);
System.out.println(list);
5.案例五,Lambda表达式写过滤器(FileFilter函数式接口)
明确作用和方法:抽象路径名的过滤器。该接口的实例可以传递给
类的File
方法。listFiles(FileFilter)
FileFilter接口的唯一抽象方法accept(File pathname)
测试指定的抽象路径名是否应包含在路径名列表中。
类的listFiles(FileFilter filter)方法介绍:
File
返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。
演示1:
1.先用匿名内部类写
// 创建文件对象,文件路径是d:\\demo
File file = new File("d:\\demo");
// file调用listFiles()直接传入过滤器的实例和pathname,返回类型是数组
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
//endsWith(".txt") 获取以.txt结尾,并且只要是文件,
return pathname.getName().endsWith(".txt") && pathname.isFile();
}
});
2.用Lambda写
//这是未简化
File[] files1 = file.listFiles((File pathname)->{return pathname.isFile() && pathname.getName().endsWith(".txt");});
//简化格式后
File[] files1 = file.listFiles( pathname -> pathname.isFile() && pathname.getName().endsWith(".txt") );