第一章、Lambda表达式与函数式接口
1.1)Lambda 表达式是什么
1.1.1)无参数无返回值的Lambda方法
Lambda 表达式本质上是一个匿名方法,是JAVA8中提供的一种新的特性(一种新的表达方式,以前旧的写法换成新的写法,可以写出更简洁、更灵活的代码)。
我们以前定义一个方法总是想到方法的五要素:
修饰符 返回值类型 方法名(参数列){
方法体
}
//--------------------------------------------
//以前写个打印方法:
public void prin(){
System.out.println(" 打印这个Lambda啊");
}
将这个无参无返回值的方法用Lambda表达式翻新成Lambda语法的方法,语法格式如下:
最简单的三要素:
参数列表 操作符箭头 方法体
() -> {System.out.println(" 打印这个Lambda啊");}
//-------------------------------------------------------------
//注意注意这段代码无法运行
() -> { System.out.println(" 打印这个Lambda啊");}
1.1.2)有一个参数,并且无返回值
在这个基础上我们进行拓展丰富,在参数列表里放入参数,增加返回值。
//有一个参数,并且无返回值;注意这段代码无法运行
参数列表里放个参数a 操作符箭头 方法体
(参数a) -> System.out.println(a);
1.1.3)多参,有返回值
在参数列表里放两个参数,有返回值。
//有两个以上的参数,有返回值,并且大括号方法体里头多条语句
Comparator com = (a, b) -> {
System.out.println("打印一下"); return Integer.compare(10, 11);
};
我们发现,Lambda语句前面多了个Comparator com = ,正是因为这段代码前面多了一个Comparator com 函数式接口,这段代码可以运行了。
1.2)函数式接口是什么
接口好理解,那什么是函数式接口呢?函数式接口是有且仅有一个抽象方法(不包含object中的方法)的接口。
注意:我们只需要关注抽象方法的个数,不用关注其他类型的方法个数。
我们可以用注解@FunctionalInterface 检测是否为函数式接口
@FunctionalInterface
interface MyFunctionalInterface {
// 只能包含一个抽象方法
void doSomething();
// 函数式接口可以可以包含默认方法和静态方法
default void doSomethingElse() {
// 默认方法的实现
}
static void anotherMethod() {
// 静态方法的实现
}
}
public class Main {
public static void main(String[] args) {
// 检测是否为函数式接口
boolean isFunctional = MyFunctionalInterface.class.isAnnotationPresent(FunctionalInterface.class);
System.out.println("是函数式接口吗?" + isFunctional);
}
}
第二章、使用Lambda
2.1)必须有一个函数式接口
看了第一章我们知道,Lambda表达式前面放普通接口是不行的,必须是Comparator 这种函数式接口。
//Consumer 是函数式接口
Consumer con = (x) -> System. out .println(x);
con.accept( "这个可以运行打印了" );
2.2)省略规则
1. 参数类型必须同时省略
2. 一个参数时,参数的括号可省略
3. 代码块里只有一句时,可省略大括号,分号和return
Comparator com = (x, y) -> Integer.compare(10, 13);
2.3)Lambda和匿名内部类比较
Lambda表达式虽然简洁,用()->
就可以代替整个匿名内部类,但只能用于函数式接口。而匿名内部类却可以用于接口,抽象类或者普通类。举个函数式接口Runnable接口的例子:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是匿名内部类里传了个Runnable的实现类对象");
}
}).start();
用Lambda
new Thread(() -> System.out.println("好家伙这么简洁")).start();
第三章、具体使用举例
我们要明确:方法体才是关键所在,Lambda表达式方法体里的方法来自哪个函数式接口,这个函数式接口的抽象方法作用是什么,才能有明确的目的去写Lambda表达式,也就是我们说的:“解决什么问题”。
3.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("打印这个字符串");
}
3.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表达式 省略格式
//参数类型必须同时省略
//一个参数时,参数的括号可省略
//代码块里只有一句时,可省略大括号,分号和return
new Thread(() -> System.out.println("Lambda表达式 启动线程...")).start();
3.3)案例三,Lambda表达式写判断型接口(Predicate函数式接口)
明确作用和方法:Predicate判断型接口,可以对数据进行条件的判断,返回判断的结果。
演示:1.第一步先创建集合list
//先创建一个集合
ArrayList<Integer> list = new ArrayList<>();
//使用addAl方法添加元素
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9);
2.用list调用removeIf()方法,
注意:因为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);
3.4)Lambda表达式写比较器(Comparator函数式接口)
明确作用和方法:Comparator函数式接口,强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator实例 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
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);
3.5)Lambda表达式写过滤器(FileFilter函数式接口)
明确作用和方法:抽象路径名的过滤器。该接口的实例可以传递给File类的listFiles(FileFilter)方法。
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") );