写 Java 的时候,你是不是也觉得以前写匿名内部类像裹了层厚棉袄?就拿创建线程来说,以前得这么写:

new Thread (new Runnable () {

@Override

public void run () {

System.out.println ("线程执行了");

}

}).start ();

光一个简单的打印,就得套好几层括号,看着都费劲。后来 Java 8 出了 Lambda 表达式,简直是救星,同样的功能,一行代码就能搞定:

new Thread (() -> System.out.println ("线程执行了")).start ();

是不是清爽多了?小索奇当初学的时候也踩过坑,刚开始总搞不懂 Lambda 的写法规则,后来拆解完发现,其实就三部分:参数、箭头、方法体,特简单。

简单说就是,Lambda 是用来简化 “函数式接口” 实现的。那啥是函数式接口?说白了就是只有一个抽象方法的接口,比如刚才的 Runnable,里面就一个 run () 方法。Java 里还有好多自带的,比如处理集合用的 Consumer、获取数据的 Supplier,都是这类。

你想想看,以前我们用匿名内部类实现这种接口,其实真正有用的就方法里的几行代码,其余的都是 “模板代码”。Lambda 就是把这些模板砍掉,只留核心逻辑,多高效。

再举个集合遍历的例子,以前遍历 List 得写 for 循环,或者增强 for 循环:

List list = Arrays.asList ("Java", "Lambda", "教程");

for (String s : list) {

System.out.println (s);

}

现在用 Lambda 配合 forEach,直接这么写:

list.forEach(s -> System.out.println(s));

要是逻辑复杂点,比如给每个元素加个前缀,也能轻松搞定,把方法体用大括号包起来就行:

list.forEach (s -> {

String newStr = "前缀_" + s;

System.out.println (newStr);

});

不过这里有个坑得提醒你,Lambda 里用外部变量的时候,那个变量必须是 final 的,或者 “事实上的 final”—— 就是说你没写 final,但从来没改过它的值。小索奇之前就因为在 Lambda 里改了外部变量的值,编译器直接报错,当时还纳闷了半天,后来才反应过来这规矩。

说到这儿可能有人会问:“那所有接口都能用 Lambda 吗?” 当然不是!必须得是函数式接口才行。要是接口里有两个抽象方法,你写 Lambda 的时候编译器都不知道该实现哪个,对吧?不过 Java 8 之后有个 @FunctionalInterface 注解,加在接口上,编译器就会帮你检查是不是符合函数式接口的要求,这个小技巧亲测有用。

还有个更偷懒的写法,叫方法引用,要是 Lambda 里就调用一个已有的方法,连参数都不用写。比如刚才的打印,还能写成这样:

list.forEach(System.out::println);

双冒号::就相当于把方法 “传给” forEach,是不是觉得很有意思?这种写法在处理集合排序的时候特别好用,比如给 User 对象按年龄排序:

List userList = ...;

userList.sort(Comparator.comparingInt(User::getAge));

比以前写 Comparator 的匿名内部类省了太多代码,这工作效率不就上来了?

你平时写 Lambda 最常用来处理什么场景?是集合遍历还是线程创建?或者有没有踩过什么特别的坑?欢迎在评论区聊聊,说不定能帮到其他刚学的朋友。

我是【即兴小索奇】,点击关注,后台回复 领取,获取更多相关资源

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐