函数式编程思想概述
在数学中,函数就是有输⼊量、输出量的⼀套计算⽅案,也就是“拿什么东⻄做什么事情”。相对
⽽⾔,⾯向对象过分强调“必须通过对象的形式来做事情”,⽽函数式思想则尽量忽略⾯向对象的
复杂语法 – 强调做什么,⽽不是以什么形式做。
⾯向对象的思想:
做⼀件事情,找⼀个能解决这个事情的对象,调⽤对象的⽅法,完成事情。
函数式编程思想:
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程。
冗余的Runnable代码
传统写法
public class Demo01Runnable {
public static void main(String[] args) {
// 匿名内部类
Runnable task = new Runnable() {
@Override
public void run() { // 覆盖重写抽象⽅法
System.out.println("多线程任务执⾏!");
}
};
new Thread(task).start(); // 启动线程
}
}
代码分析
对于 Runnable 的匿名内部类⽤法,可以分析出⼏点内容:
Thread 类需要 Runnable 接⼝作为参数,其中的抽象 run ⽅法是⽤来指定线程任务内容的核
⼼;
为了指定 run 的⽅法体,不得不需要 Runnable 接⼝的实现类;
为了省去定义⼀个 RunnableImpl 实现类的麻烦,不得不使⽤匿名内部类;
必须覆盖重写抽象 run ⽅法,所以⽅法名称、⽅法参数、⽅法返回值不得不再写⼀遍,且不
能写错;
⽽实际上,似乎只有⽅法体才是关键所在。
体验Lambda的更优写法
public class Demo02LambdaRunnable {
public static void main(String[] args) {
new Thread(() -> System.out.println("多线程任务执⾏!")).start(); // 启动线
程
}
}
这段代码和刚才的执⾏效果是完全⼀样的,可以在1.8或更⾼的编译级别下通过。从代码的语义
中可以看出:我们启动了⼀个线程,⽽线程任务的内容以⼀种更加简洁的形式被指定。
不再有“不得不创建接⼝对象”的束缚,不再有“抽象⽅法覆盖重写”的负担,就是这么简单!
回顾匿名内部类
在上例中,核⼼代码其实只是如下所示的内容:
() -> System.out.println("多线程任务执⾏!")
使⽤实现类
要启动⼀个线程,需要创建⼀个 Thread 类的对象并调⽤ start ⽅法。⽽为了指定线程执⾏的内
容,需要调⽤ Thread 类的构造⽅法:
public Thread(Runnable target)
为了获取 Runnable 接⼝的实现对象,可以为该接⼝定义⼀个实现类 RunnableImpl :
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println("多线程任务执⾏!");
}
}
然后创建该实现类的对象作为 Thread 类的构造参数:
public class Demo03ThreadInitParam {
public static void main(String[] args) {
Runnable task = new RunnableImpl();
new Thread(task).start();
}
}
使⽤匿名内部类
这个 RunnableImpl 类只是为了实现 Runnable 接⼝⽽存在的,⽽且仅被使⽤了唯⼀⼀次,所以使
⽤匿名内部类的语法即可省去该类的单独定义,即匿名内部类:
public class Demo04ThreadNameless {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("多线程任务执⾏!");
}
}).start();
}
}
匿名内部类的好处与弊端
⼀⽅⾯,匿名内部类可以帮我们省去实现类的定义;另⼀⽅⾯,匿名内部类的语法 – 确实太复
杂了!
语义分析
仔细分析该代码中的语义, Runnable 接⼝只有⼀个 run ⽅法的定义:
public abstract void run();
即制定了⼀种做事情的⽅案(其实就是⼀个函数):
⽆参数:不需要任何条件即可执⾏该⽅案。
⽆返回值:该⽅案不产⽣任何结果。
代码块(⽅法体):该⽅案的具体执⾏步骤。
同样的语义体现在 Lambda 语法中,要更加简单:
() -> System.out.println("多线程任务执⾏!")
前⾯的⼀对⼩括号即 run ⽅法的参数(⽆),代表不需要任何条件;
中间的⼀个箭头代表将前⾯的参数传递给后⾯的代码;
后⾯的输出语句即业务逻辑代码。
** Lambda标准格式**
(参数类型 参数名称) -> { 代码语句 }
格式说明:
⼩括号内的语法与传统⽅法参数列表⼀致:⽆参数则留空;多个参数则⽤逗号分隔。
-> 是新引⼊的语法格式,代表指向动作。
⼤括号内的语法与传统⽅法体要求基本⼀致。