记录时间 [2024-08-16]
前置知识:Java 基础篇;Java 面向对象
多线程 01:Java 多线程学习导航,线程简介,线程相关概念的整理
多线程 02:线程实现,创建线程的三种方式,通过多线程下载图片案例分析异同(Thread,Runnable,Callable)
Java 多线程学习主要模块包括:线程简介;线程实现;线程控制;线程状态;线程同步;线程通信问题;拓展高级主题。
本文是针对多线程的相关知识补充:静态代理与 Lambda
表达式。
文章通过婚庆公司代理婚礼策划的案例讲解了静态代理这一模式,并类比了 Thread
类代理 Runnable
接口启动多线程的方式。
此外,文章通过对内部类的简化,进行 Lambda
表达式的推导,并介绍了 Lambda
表达式的使用方式和注意点,同时类比 Runnable
接口这个函数式接口,讲述如何使用 Lambda
表达式创建 Runnable
对象。
静态代理是一种设计模式,常用于 Java 中实现面向切面编程(AOP)、装饰者模式等。
在静态代理中,代理类是在编译时就已经定义好的,并且与被代理的对象具有相同的接口。
代理类可以用来包装真实对象的方法调用,从而可以在调用前后添加额外的操作。
静态代理通常包含以下几个部分:
我们可以使用静态代理模式来模拟结婚与婚庆公司的行为。
在这个例子中,假设某人要举办一场婚礼,他需要婚庆公司来帮忙安排婚礼策划的各个方面。
首先,我们定义一个 Marry
接口,它表示婚礼策划服务。同时定义一个 HappyMarry()
方法。
interface Marry {
// 人间四大喜事
// 久旱逢甘霖,他乡遇故知,洞房花烛夜,金榜题名时。
void HappyMarry();
}
创建一个 Person
类,它代表真实对象,需要实现 Marry
接口,并实现接口中的方法。
// 真实角色,结婚当事人
class Person implements Marry {
@Override
public void HappyMarry() {
System.out.println("某人要结婚了,超开心");
}
}
创建一个 WeddingCompany
类,它是代理角色,帮助目标对象安排婚礼策划的各个方面。
代理类也需要实现 Marry
接口,并实现接口中的方法。
同时,代理类中包装了一个真实的 Marry
对象。代理类将在计划婚礼前后添加额外的行为,比如咨询、准备和清理工作。
// 代理角色,帮助目标对象安排婚礼策划的各个方面
class WeddingCompany implements Marry {
// 包装一个真实的结婚对象
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
@Override
public void HappyMarry() {
before();
// 实际上是某人要结婚
this.target.HappyMarry();
after();
}
private void before() {
System.out.println("婚礼之前,布置现场");
}
private void after() {
System.out.println("婚礼之后,清理工作");
}
}
最后,我们在主程序中使用代理对象来调用 HappyMarry()
方法。
在代理对象中传入真实对象,然后调用方法。
public class WeddingDemo {
public static void main(String[] args) {
// 真实对象
Person person = new Person();
// 代理对象
WeddingCompany proxy = new WeddingCompany(person);
// // 代理对象调用方法
proxy.HappyMarry();
// 合起来写
// new WeddingCompany(new Person()).HappyMarry();
}
}
当运行 WeddingDemo
类时,输出应该是这样的:
婚礼之前,布置现场
某人要结婚了,超开心
婚礼之后,清理工作
静态代理模式总结:
静态代理模式的优点:
在 Java 中,通过 Thread
类代理 Runnable
接口启动多线程是一种常见的模式。
这种模式类似于静态代理模式,这里的代理行为由 Thread
类完成的。
在这个模式中,Thread
类扮演了代理的角色,它代理了 Runnable
接口的实现,并且负责启动线程。我们可以将 Thread
类看作是代理类,它包装了一个实现了 Runnable
接口的对象,并在适当的时机调用其run()
方法。
Runnable
接口,定义了线程执行的行为。Runnable
接口的类,提供了实际要执行的任务。Thread
类,它代理了 Runnable
接口的实现,并负责启动和管理线程。例如:
// lambda 表达式
new Thread( ()-> System.out.println("线程") ).start();
Lambda
表达式是 Java 8 引入的一项重要功能,它允许定义简洁的一次性使用的函数。
Lambda
表达式简化了代码的编写,通常用于实现函数式接口(只有一个抽象方法的接口)。
对于函数式接口,可以通过 Lambda
表达式来创建该接口的对象。
Lambda
表达式的语法格式如下:
parameters
:参数列表。->
:箭头符号,表示参数列表之后跟着的是主体部分。expression
或 { statements; }
:主体部分,可以是一个表达式或一组语句。(parameters) -> expression
// 或者
(parameters) -> {
statements;
// statements2;
}
无参数的 Lambda
表达式:
// () -> System.out.println("Hello, Lambda!");
Runnable task = () -> System.out.println("Hello, Lambda!");
task.run();
单参数的 Lambda
表达式:
// (int a) -> System.out.println("Hello, Lambda!" + a);
Runnable task = (int a) -> System.out.println("Hello, Lambda!" + a);
task.run();
多参数的 Lambda
表达式:
// (int a, int b) -> System.out.println("...");
Runnable task = (int a, int b) -> System.out.println("Hello, Lambda!" + a);
task.run();
Lambda
表达式使用前提:接口为函数式接口。Lambda
表达式的主体部分只有一个表达式,可以不用 {}
包裹;多行代码需要用 {}
包裹,表示为一个整体的代码块。Lambda
表达式的参数列表中只有一个参数时,括号、参数类型可以省略。例如,(int a)
可以简化成 a
。(int a, int b, int c)
可以简化成 (a, b, c)
。以下是使用 Lambda
表达式的几个主要原因:
例如,可以用一行代码定义一个方法,而不是写一个完整的内部类。
传统的内部类方式:
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("Hello, Lambda!");
}
};
使用 Lambda
表达式:
Runnable task = () -> System.out.println("Hello, Lambda!");
接下来,我们通过对内部类的简化,进行 Lambda
表达式的推导。
定义一个函数式接口 ILike
,它只有一个抽象方法 lambda()
。
// 1. 定义一个函数式接口
interface ILike {
// 函数式编程,有且仅有一个抽象方法
public abstract void lambda();
}
定义一个 Like
类去实现 ILike
接口。
// 2. 实现类(外部):定义一个类去实现接口
class Like implements ILike {
// 实现接口的抽象方法
@Override
public void lambda() {
System.out.println("Test Lambda Like...");
}
}
// 主方法中
ILike like = new Like();
like.lambda();
简化:定义一个静态内部类 Like2
去实现 ILike
接口。
// 3. 静态内部类
static class Like2 implements ILike {
// 实现接口的抽象方法
@Override
public void lambda() {
System.out.println("Test Lambda Like2...");
}
}
// 主方法中
like = new Like2();
like.lambda();
简化:定义一个局部内部类 Like3
去实现 ILike
接口。
// 4. 局部(成员)内部类
class Like3 implements ILike {
// 实现接口的抽象方法
@Override
public void lambda() {
System.out.println("Test Lambda Like3...");
}
}
// 主方法中
like = new Like3();
like.lambda();
简化:定义一个匿名内部类去实现 ILike
接口。
// 5. 匿名内部类,没有名称的类,必须借助接口或者父类
like = new ILike() {
@Override
public void lambda() {
System.out.println("Test Lambda Like4...");
}
};
like.lambda();
用 Lambda
表达式进行简化。一个简化的过程,只保留最核心的代码。
// 6. 用 Lambda 表达式进行简化
// 一个简化的过程,只保留最核心的代码
like = ()-> {
System.out.println("Test Lambda Like5...");
};
like.lambda();
Runnable
接口定义:
public interface Runnable {
public abstract void run();
}
在 Java 中,函数式接口是指一个接口中只定义了一个抽象方法的接口。
Runnable
接口中只包含一个抽象方法 run()
,符合这个定义。因而 Runnable
接口是一个函数式接口,可以被 Lambda
表达式所使用。
使用 Lambda
表达式创建 Runnable
对象:
// Runnable task = () -> System.out.println("Hello, Runnable!");
public class RunnableExample {
public static void main(String[] args) {
// 使用 Lambda 表达式创建 Runnable 对象
Runnable task = () -> System.out.println("Hello, Runnable!");
// 创建 Thread 对象,并传入 Runnable 对象
Thread thread = new Thread(task);
// 启动线程
thread.start();
}
}
狂神说 Java 多线程:https://www.bilibili.com/video/BV1V4411p7EF
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/
MVN 仓库:https://mvnrepository.com/