概述
函数式编程思想
在数学中 函数就是有输入量和输出量的一套计算方案 也就是“拿什么东西做什么事情”
相对而言 面向对象过分强调必须通过对象的形式来做事情
而函数式思想则尽量忽略面向对象的复杂语法——强调做什么 而不是以什么形式做
面向对象的思想:
做一件事情 找一个能解决这个事情的对象 调用对象的方法 完成事情
函数式编程思想:
只要能获取到结果 谁去做的 怎么做的都不重要,重视的是结果 不重视过程
可能不太好理解 我们举个简单的栗子:
代码冗余
public static void main(String[] args) {
RunnableImpl runnable=new RunnableImpl();
Thread thread=new Thread(runnable);
thread.start();
// 使用匿名内部类简化
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " - new");
}
};
new Thread(runnable1).start();
// 继续简化
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " - new");
}
}).start();
}
在这段多线程代码中:
1、Thread 类需要 Runnable 接口作为参数 因为其中的抽象 run 方法是用来指定线程任务内容的核心
2、为了指定 run 的方法体 不得不需要存在一个Runnable接口的实现类
3、为了省去定义一个RunnableImpl实现类的麻烦 不得不使用匿名内部类
4、因为必须覆盖重写抽象的run方法 所以方法名称 方法参数和方法返回值都不得不再写一遍 且不能写错
而实际上 只有方法体才是关键所在
因此 我们需要转换我们的编程思想
更加关注做什么 而不是怎么做
我们为了做这件事情而不得不创建一个匿名内部类对象
而我们真正希望做的事情是将 run 方法体内的代码传递给 Thread 类
传递一段代码——这才是真正的目的
更加简便:
在2014年3月Oracle所发布的Java 8(JDK 1.8)中 加入了Lambda表达式的重量级新特性 打开了新世界的大门
如下案例:
public static void main(String[] args) {
// 使用匿名内部类的方式实现多线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " - new");
}
}).start();
//使用Lambda表达式实现多线程
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " - new");
}
).start();
}
我们来详细看一下:
Runnable 接口只有一个 run 方法的定义:public abstract void run()
即制定了一种做事情的方案(其实就是一个函数):
无参数:不需要任何条件即可执行该方案
无返回值:该方案不产生任何结果
代码块(方法体):该方案的具体执行步骤
在Lambda表达式中更为简单:() ‐> System.out.println("方法执行")
前面的一对小括号即 run 方法的参数(无) 代表不需要任何条件
中间的一个箭头代表将前面的参数传递给后面的代码
后面的输出语句即业务逻辑代码
一、Lambda表达式的标准格式
Lambda省去了面向对象语法的条条框框
格式由3个部分组成:
一些参数
一个箭头
一段代码
标准格式:
(参数类型 参数名称) ‐> { 代码语句 }
小括号内的语法与传统方法参数列表一致:无参数则留空 多个参数则用逗号分隔
-> 是新引入的语法格式 代表指向动作
大括号内的语法与传统方法体要求基本一致
二、案例:
1、无参数无返回值
接口类:
public interface Cook {
public abstract void makeFood();
}
测试类:
public class CookTest {
public static void main(String[] args) {
// 调用invokeCook()方法 传递Cook接口的匿名内部类对象
invokeCook(new Cook() {
@Override
public void makeFood() {
System.out.println("开饭了");
}
});
// 使用Lambda表达式简化匿名内部类的书写
invokeCook(() -> {
System.out.println("开饭了");
});
}
// 定义一个方法 参数传递Cook接口 方法内部调用Cook接口中的makeFood()方法
public static void invokeCook(Cook cook)
{
cook.makeFood();
}
}
2、有参数有返回值
例一、
实体类:
public class Person {
private String name;
private int age;
...
}
测试类:
public class ArraysTest {
public static void main(String[] args) {
// 使用数组存储多个Person对象
Person[] arr={new Person("小A",10),
new Person("小B",13),
new Person("小C",12)};
// 升序操作
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge()-o2.getAge();
}
});
// 使用Lambda表达式简化匿名内部类的书写
Arrays.sort(arr,(Person o1, Person o2) -> {
return o1.getAge()-o2.getAge();
});
// 遍历输出结果
for (Person p:arr)
{
System.out.println(p);
}
}
}
例二、
计算类:
public interface Calculate {
public abstract int calc(int a,int b);
}
测试类:
public class CalculateTest {
public static void main(String[] args) {
// 调用方法 参数是一个接口 可以使用匿名内部类
invokeCalc(1, 2, new Calculate() {
@Override
public int calc(int a, int b) {
return a+b;
}
});
// 使用Lambda表达式简化匿名内部类的书写
invokeCalc(1,2,(int a,int b) -> {
return a+b;
});
}
// 参数传递两个int类型的整数和Calculate接口 内部调用方法计算两个整数的和
public static void invokeCalc(int a,int b,Calculate calculate)
{
System.out.println(calculate.calc(a, b));
}
}
三、Lambda省略格式
Lambda表达式是可推导可省略的
凡是根据上下文推导出来的内容 都可以省略书写
可省略的内容:
1、参数列表:括号中参数列表的数据类型可以省略不写 因为在接口里已经定义了类型
2、参数列表:括号中的参数如果只有一个 那么类型和()都可以省略
3、代码:如果{}中的代码只有一行 那么无论是否有返回值 都可以省略{}和return和分号 但要省略必须一起省略
public static void main(String[] args) {
// 在JDK1.7版本之前 必须把前后的泛型都写上
ArrayList arrayList1=new ArrayList();
// 在JDK1.7版本之后 等号后的泛型可省略 因为可以根据前面的泛型推导出来
ArrayList arrayList2=new ArrayList<>();
}
案例
无参数无返回值:
// 调用invokeCook()方法 传递Cook接口的匿名内部类对象
invokeCook(new Cook() {
@Override
public void makeFood() {
System.out.println("开饭了");
}
});
// 使用Lambda表达式简化匿名内部类的书写
invokeCook(() -> {
System.out.println("吃饭了");
});
// 优化省略Lambda ★
invokeCook(() -> System.out.println("吃饭了"));
有参数有返回值:
// 调用方法 参数是一个接口 可以使用匿名内部类
invokeCalc(1, 2, new Calculate() {
@Override
public int calc(int a, int b) {
return a+b;
}
});
// 使用Lambda表达式简化匿名内部类的书写
invokeCalc(1,2,(int a,int b) -> {
return a+b;
});
// 优化省略Lambda ★
invokeCalc(1,2,(a,b) -> a+b);
总结:
1、使用Lambda必须具有接口 且要求接口中有且仅有一个抽象方法
因此 无论是JDK内置的 Runnable 接口或 Comparator 接口还是自定义的接口 只有当接口中的抽象方法存在且唯一时 才可使用Lambda
因为如果有多个抽象方法的话 就不知道调用哪个抽象方法了
2、使用Lambda必须具有上下文推断
也就是方法的参数或局部变量类型必须为Lambda对应的接口类型 才能使用Lambda作为该接口的实例
注:有且仅有一个抽象方法的接口称为函数式接口
最后
以上就是阳光大船为你收集整理的java 箭头函数_Java8的Lambda表达式(箭头函数)的全部内容,希望文章能够帮你解决java 箭头函数_Java8的Lambda表达式(箭头函数)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复