Java基础 第五节 第五课
概述
在兼顾面向对象特性的基础上, Java 语言通过 Lambda 表达式与方法引用等, 为开发者打开了函数式编程的大门.
Lambda 的延迟执行
有些场景的代码执行后, 结果不一定会被使用, 从而造成性能浪费. 而 Lambda 表达式是延时执行的, 这正好可以作为解决方案, 提升性能.
性能浪费的日志案例
日志可以帮助我们快速的定位问题, 记录程序运行过程中的情况, 以便项目的监控和优化.
一种典型的场景就是对参数进行有条件使用. 例如对日志消息进行拼接后, 在满足条件的情况下进行打印输出:
public class Logger {
private static void log(int level, String msg) {
if (level == 1) {
System.out.println(msg);
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(1, msgA + msgB + msgC);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
这段代码存在的问题:
无论级别是否满足要求, 作为 log 方法的第二个参数, 三个字符串一定会首先被拼接并传入方法内, 然后才会进行级别判断. 如果级别不符合要求, 那么字符串的拼接操作就白做了, 存在性能浪费.
体验 Lambda 的更优写法
使用 Lambda 必然需要一个函数式接口:
@FunctionalInterface
public interface MessageBuilder {
String buildMessage();
}
- 1
- 2
- 3
- 4
然后对 log 方法进行改造:
public class Test {
private static void log(int level, MessageBuilder builder){
if(level == 1){
System.out.println(builder.buildMessage());
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(1, () -> msgA + msgB + msgC);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
这样一来, 只有当级别满足要求的时候, 才会进行三个字符串的拼接. 否则三个字符串将不会进行拼接.
证明 Lambda 的延迟
下面的代码可以通过结果进行验证:
public class Test {
private static void log(int level, MessageBuilder builder) {
if (level == 0) {
System.out.println(builder.buildMessage());
}
}
public static void main(String[] args) {
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";
log(1, () -> {
System.out.println("Lambda 执行!");
return msgA + msgB + msgC;
});
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
从结果中可以看出, 在不符合级别的情况下, Lambda 将不会执行. 从而达到节省性能的效果.
扩展:
实际上使用内部类也可以达到同样的效果. 只是将代码操作延迟到了另外一个对象当中通过调用方法来完成. 而是否调用其所在方法是在条件判断之后才执行的.
使用 Lambda 作为参数和返回值
如果抛开实现原理不说, Java 中的 Lambda 表达式可以被当做是匿名内部类的替代品. 如果方法的参数是一个函数式接口类型, 那么就可以使用 Lambda 表达式进行替代. 使用 Lambda 表达作为方法参数, 其实就是使用函数式接口作为方法参数.
例如java.lang.Runnable接口就是一个函数式接口. 假设有一个 startThread 方法使用该接口作为参数, 那么就可以使用 Lambda 进行传参. 这种情况其实和 Thread 类的构造方法参数为 Runnable 没有本质区别.
public class Test {
private static void startThread(Runnable task) {
new Thread(task).start();
}
public static void main(String[] args) {
startThread(() -> System.out.println("线程任务执行 !"));
}
}
输出结果:
"线程任务执行 !"
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
类似地, 如果一个方法的返回值类型是一个函数式接口, 那么就可以直接返回一个 Lambda 表达式. 当需要通过一个方法来获取一个```java.util,Comparator``接口类型的对象作为排序器时, 就可以调用该方法获取.
import java.util.Arrays;
import java.util.Comparator;
public class Test {
private static Comparator<String> Compare() {
return (a, b) -> b.length() - a.length();
}
public static void main(String[] args) {
String[] array = {"abc", "ab", "abcd"};
System.out.println(Arrays.toString(array));
Arrays.sort(array, Compare());
System.out.println(Arrays.toString(array));
}
}
输出结果:
[abc, ab, abcd]
[abcd, abc, ab]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
其中直接 return 一个 Lambda 表达式即可.
文章来源: iamarookie.blog.csdn.net,作者:我是小白呀,版权归原作者所有,如需转载,请联系作者。
原文链接:iamarookie.blog.csdn.net/article/details/111777603
- 点赞
- 收藏
- 关注作者
评论(0)