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)