一、函数式编程思想概述
https://www.runoob.com/java/java8-lambda-expressions.html
在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”
面向对象强调“必须通过对象的形式来做事情”,做事情之前首先要创建一个对象
函数式思想则尽量忽略面向对象的复杂语法:”强调做什么,而不是以什么形式去做”,我们要学习的Lambda表达式就是函数式思想的体现
什么是函数式接口呢?就是一个接口有且只有一个抽象方法。
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
1.1需求:启动一个线程,在控制台输出一句话:多线程启动了
1.1.1 方式一 创建类实现Runnable接口
定义一个类MyRunnable实现Runnable接口,重写run()方法
创建MyRunable类对象
创建Thread类的对象,把MyRunnable的对象作为构造参数传递
启动线程
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("多线程程序启动了");
}
}
public class LambdaTest {
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
Thread t = new Thread(my);
t.start();
}
}
1.1.2 方式二 匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("ssss");
}
}).start();
1.1.3 方式三 lambda表达式
简洁,不用创建类
new Thread( ()->{
System.out.println("多线程程序启动");
}).start();
1.2 Lambda表达式的代码式使用分析
new Thread( ()->{
System.out.println("多线程程序启动");
}).start();
():里面没有内容,可以看成是方法形式参数为空
->:用箭头指向后面要做的事情
{}:包含一段代码。我们称之为代码块
(形式参数)->{代码块}
形式参数:如果有多个参数,参数之间用逗号隔开。
类似于方法的形参列表,这里指的是函数式接口中抽象方法的参数。参数的类型即可以声明也可以省略,如果只有一个参数,括号也可以省略
->:由英文中划线和大于符号组成,固定写法,代表指向动作
代码块:我们具体要做的事情
二、Lambda表达式练习
2.1 抽象方法无参无返回值
![](https://img-blog.csdnimg.cn/img_convert/2e46fff87a0bd164cf242002400d0dd8.png)
public interface Eatable {
void eat();
}
public class EatableImpl implements Eatable{
@Override
public void eat() {
System.out.println("好好好");
}
}
public class EatableDemo {
public static void main(String[] args) {
Eatable e = new EatableImpl();
userEatable(e);
}
private static void userEatable(Eatable e){
e.eat();
}
}
上面的代码可以简化
userEatable(()->{
System.out.println("好好好");
} );
下面这个就不需要实现类的
public class EatableDemo {
public static void main(String[] args) {
userEatable(()->{
System.out.println("好好好");
} );
}
private static void userEatable(Eatable e){
e.eat();
}
}
2.1.1 匿名内部类与lambda表达式直接对比
@FunctionalInterface
public interface AcanthopanaxInterface {
void get();
}
public class Test03 {
public static void main(String[] args) {
// 1.使用匿名内部类的方式进行
new AcanthopanaxInterface(){
@Override
public void get() {
System.out.println("get");
}
}.get();
// 2.lambda表达式
AcanthopanaxInterface acanthopanaxInterface = () -> {
System.out.println("使用lambda表达式的调用方法");
};
acanthopanaxInterface.get();
}
}
2.2 抽象方法带参无返回值
![](https://img-blog.csdnimg.cn/img_convert/dac27c3d943f39f11d717db877819cbd.png)
定义接口
public interface Flyable {
void fly(String s);
}
public class FlyableDemo {
public static void main(String[] args) {
userFlyable( (String s)->{
System.out.println(s);
System.out.println("好好好");
});
}
private static void userFlyable(Flyable f){
f.fly("风和日丽");
}
}
![](https://img-blog.csdnimg.cn/img_convert/20203fc8422f207f08500cf44f0de010.png)
拆开看一下
public class FlyableDemo {
public static void main(String[] args) {
Flyable flyable = (String s) -> {
System.out.println(s);
System.out.println("好好好");
};
userFlyable(flyable);
}
private static void userFlyable(Flyable f){
f.fly("风和日丽");
}
}
2.3 抽象方法带参带返回值
![](https://img-blog.csdnimg.cn/img_convert/f062050e47a162216b08918a763b44f4.png)
public class AddableDemo {
public static void main(String[] args) {
userAddable( (int x,int y)->{
return x+y;
});
}
private static void userAddable(Addable a){
int sum = a.add(10,20);
System.out.println(sum);
}
}
a.add(10,20)中的10和20最终传递给了int x,int y,然后通过lambda表达式将x与y相加并返回给sum
public interface Addable {
int add(int x,int y);
}
如果上面的不好理解我们就拆分出来
一定要看一下注释信息
public class AddableDemo {
public static void main(String[] args) {
// Addable addable = (x, y) -> {
// return x + y;
// };
// 下面的程序就是这句话userAddable(addable);
userAddable((x, y) -> {
return x + y;
});
}
private static void userAddable(Addable a){
int sum = a.add(10,20);
System.out.println(sum);
}
}
2.3.1 匿名内部类与lambda表达式的对比
@FunctionalInterface
public interface YouShenInterface {
String get(int i,int j);
}
public class Test04 {
public static void main(String[] args) {
// 1.匿名内部类的形式
YouShenInterface youShenInterface = new YouShenInterface() {
@Override
public String get(int i, int j) {
return i + "---" + j;
}
};
System.out.println(youShenInterface.get(1,1));
// 2. lambda表达式的形式
YouShenInterface youShenInterface1 = (i, j) -> {
return i + "---" + j;
};
System.out.println(youShenInterface1.get(1,2));
}
}
![](https://img-blog.csdnimg.cn/img_convert/5589ceb4313d9a423249231fe7c04bd7.png)
三、Lambda表达式的省略模式
3.1 参数的类型可以省略
虽然能省略,但是多个参数的情况下不能只省略一个
userAddable( ( x, y)->{
return x+y;
});
3.2 参数有且只有一个,参数可以省略
public class FlyableDemo {
public static void main(String[] args) {
userFlyable( s->{
System.out.println(s);
});
}
private static void userFlyable(Flyable f){
f.fly("风和日丽");
}
}
3.3 代码块语句只有一条,可以省略大括号和分号
public class FlyableDemo {
public static void main(String[] args) {
userFlyable( s->System.out.println(s) );
}
private static void userFlyable(Flyable f){
f.fly("风和日丽");
}
}
3.4 代码块语句只有一条,return也要省略掉
userAddable( ( x, y)-> x+y);
四、注意事项
有一个接口(抽象类不可以),接口中有且只有一个抽象方法
使用lambda的时候必须有上下文环境,才能推导出Lambda对应的接口
![](https://img-blog.csdnimg.cn/img_convert/14bf6449b1225816d0c7a5004ee6599d.png)
匿名内部类编译之后会多出一个“.class”文件,而lambda不会多出,lambda字节码会在运行的时候动态生成
匿名内部类可以是接口,可以是抽象类,还可以是具体类
@ FunctionalInterface 表示该接口为函数接口
@FunctionalInterface
public interface OrderService {
void get();
}
如下图所示,如果我们再增加一个方法,就会报错
![](https://img-blog.csdnimg.cn/img_convert/a409f9f9db56cdec83ca0c11e01f984e.png)
但是我们可以写默认方法
![](https://img-blog.csdnimg.cn/img_convert/bb63628671407c8cd259d2d599e9f385.png)
Object父类中的方法可以在函数接口中重写
![](https://img-blog.csdnimg.cn/img_convert/b73330da1b5206dc0641ebd3b5387211.png)
五、集合的遍历与排序
5.1 集合的遍历
public class Test06 {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("mayikt");
arrayList.add("zhangin");
arrayList.add("asdasfg");
// 1.匿名内部类的形式
arrayList.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
// 2.lambda表达式的形式
arrayList.forEach(s->{
System.out.println(s);
});
}
}
5.2 集合的排序
public class Test07 {
public static void main(String[] args) {
ArrayList<UserEntity> userEntityArrayList = new ArrayList<>();
userEntityArrayList.add(new UserEntity("zhangjingqi",30));
userEntityArrayList.add(new UserEntity("fanusbisf",18));
userEntityArrayList.add(new UserEntity("saffawfasx",25));
// 1.匿名内部类排序
userEntityArrayList.sort(new Comparator<UserEntity>() {
@Override
public int compare(UserEntity o1, UserEntity o2) {
return o1.getAge()-o2.getAge();
}
});
userEntityArrayList.forEach((userEntity)->{
System.out.println(userEntity);
});
System.out.println("*************************************");
// 2.lambda表达式排序
userEntityArrayList.sort((o1,o2)->{
return o1.getAge()-o2.getAge();
});
userEntityArrayList.forEach((userEntity)->{
System.out.println(userEntity);
});
}
}