[Java8]_[语言特性]_[Lambda表达式说明]

本文深入探讨Java 8中引入的Lambda表达式,解释其如何简化代码,提高性能,以及在Comparator和Runnable等场景中的应用。文章还介绍了Lambda表达式的语法、@FunctionalInterface注解的使用,以及如何通过方法引用进一步精简代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

  1. 我们在使用 JavaComparator 进行排序, 或Runnable进行运行线程时总是需要 new 一个新的匿名类出来, 并且需要实现抽象方法,有么有更方便的做法呢?

  2. Java SE 8开始已经可以支持Lambda表达式,它如何使用呢?

说明

  1. Lambda 表达式出现以前, 我们实现一个 Comparator 比较器需要new一个匿名类, 并重写compare方法, 编译器编译时还是生成这个匿名内部类的.class文件. 这种匿名内部类借助IDE生成时并不麻烦, 但是如果进行函数流式调用, a.x(new Comparator(){...}).y(new Comparator(){...})这样的话看起来就不直观了. 除此以外生成大量的.class文件总是看起来很冗余.
ls.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
  1. Lambda出现以后对于内部类的使用是一种补充,在函数式编程时,比如上边说的流式调用很方便直观,因为我们传入的lambda表达式是一个匿名函数, 更直观易懂,代码量少,减少大括号,圆括号的视觉干扰.
ls.sort((a,b)->b.compareTo(a));
  1. Lambda调用不需要生成匿名内部类, 调用更快,性能更高. 因为JDK8实现Lambda调用方式是通过Invokedynamic指令的.

  2. 它本质上就是一个匿名函数,遵守函数的声明规则. 即参数,函数体,返回值.

  3. Lambda表达式也是实现了一个函数接口的唯一抽象方法,所以它一定对应着某个函数接口@FunctionalInterface的唯一抽象方法.

@FunctionalInterface 
interface Visitor<T>{
    T visitor(T from);
}

  1. Lambda表达式方法体内引用的this是外部方法的实例对象,Lambda表达式并不是匿名内部类,只是一个函数,并没有自己的this.

  2. Lambda实现的的函数接口必须是具有唯一抽象方法的接口,我们可以用@FunctionalInterface注解来限制这个接口,提供编译时检查。当然如果有接口只有唯一抽象方法,不声明@FunctionalInterface也行.

语法

  1. 例子: 以下是Comparator接口的方法, 我们看看Lambda表达式有几种写法.
public int compare(String a, String b){
    return a.compareTo(b);
}

方式1

  1. 参数类型可省略,会根据方法原型自动推导为String,单语句时可以省略大括号和return;以下b.compareTo(a)编译器会根据compare抽象方法原型自动推导是否需要返回.
(a,b)->b.compareTo(a)

方式2

  1. 有参数类型, 有大括号, 有return; 注意有大括号是方法原型如果需要返回,那么return不能省略.
(String a,String b)->{
    return b.compareTo(a);
}

方式3

  1. 方法引用是紧凑的lambda表达式, 直接用String的compareTo方法.
String::compareTo

例子

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@FunctionalInterface 
interface Visitor<T>{
    T visitor(T from);
}

// 不需要注释 @FunctionalInterface
// 但是如果用于 lambda实现,编译器默认它为 @FunctionalInterface
// 一个接口如果声明了多个抽象方法,在应用 lambda 表达式时会报错.
interface Book{
    String query(String name);
}

// 不允许抽象类作为lambda表达式的函数接口,在应用 lambda表达式时编译报错.
abstract class Test1
{
    abstract String query(String name);
}

public class TestLambda<T>{

    private String name = "TestLambda";

    public static void PRINT(String str){
        System.out.println(str);
    }

    public static <T> void PRINTC(Collection<T> ls){
        // Java8允许你通过::关键字获取方法或者构造函数的的引用
        ls.forEach(System.out::println);
    }

    public void testLambda3(){
        PRINT("================== testLambda3 ===================");
        Book b = (s)->{
            // this 引用的是当前方法的实例对象.
            // 而匿名类引用的是匿名类的实例.
            return s+"->"+this.name;
        };
        String s = b.query("Tobey");
        PRINT(s);
    }

    public static void testLambda2() {

        // 1. 未声明 @FunctionalInterface 的具有单个抽象方法的接口也能使用.
        PRINT("================== testLambda2 ===================");
        Book b = (s)->(s+"->");
        String s = b.query("Tobey");
        PRINT(s);

        PRINT("=====================================");
        // The target type of this expression must be a functional interface
        // Test1 t1 = (s)->(s+"->");

        // 2. Stream 类使用.
        List<String> ls = Arrays.asList("123","hello","Tobey","go home");
        Stream<String> ss = ls.stream();

        List<String> ls1 = ss.filter(s1->s1.matches("^\\d+$")).collect(Collectors.toList());
        PRINTC(ls1);

    }

    public static void testLambda(){
        PRINT("================== testLambda ===================");
        List<String> ls = Arrays.asList("csdn","infoworld","1","db","c2","2");
        PRINTC(ls);

        // 传统使用匿名类来创建比较器.
        PRINT("================= Old Comparator ====================");
        ls.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        PRINTC(ls);

        // 2. 使用lambda表达式来实现比较器,不带参数类型,因为编译器会自动推导.
        PRINT("================= Use Lambda ====================");
        ls.sort((a,b)->b.compareTo(a));
        PRINTC(ls);

        // 2.1 参数带类型, 使用{语句;}
        PRINT("=====================================");
        ls.sort((String a, String b)->{return a.compareTo(b);});
        PRINTC(ls);

       
        // 2.2 lambda表达式实现了Runnable的run()方法.
        //    -- 注意 Runnable接口声明了@FunctionalInterface注解.
        try{
            Thread t = new Thread(()->{
                PRINT("Lambda instead of anonymous Runnable");
            });
            t.start();
            t.join();
        }catch(Exception e){}
        
        // 3. lambda访问外部的final变量, 如果变量在上下文未被修改,会自动声明为final.
        //    -- 额外条件如果长度是2的,排在前面.
        PRINT("=====================================");
        int number = 2;
        ls.sort((String a, String b)->{
            
            // 编译报错:
            // Local variable number defined in an enclosing scope must be final or effectively final
            // number = 4;
            if(a.length() == number)
                return -1;
            
            if(b.length() == number)
                return 1;

            return a.compareTo(b);
        });

        PRINTC(ls);

       // 4. 声明注解为 @FunctionalInterface的接口,使用lambda表达式可以绑定默认的抽象方法.
       //    -- 注意Comparator接口声明@FunctionalInterface注解.
       //    -- 使用这种方式可以定义自己的方法参数支持lambda表达式.
       //    -- 如果只有一个参数,可把()都省略.
       PRINT("=====================================");
       Visitor<String> vs = a->{
          PRINT(a);
          return a+"-"+String.valueOf(a.hashCode());
       };
       String value = vs.visitor("infoworld");
       PRINT(value);
    }

    public static void main(String[] args) {
        System.out.println("Hello Tobey!");
        testLambda();
        testLambda2();
        new TestLambda<>().testLambda3();
    }
}

输出

Hello Tobey!
================== testLambda ===================
csdn
infoworld
1
db
c2
2
================= Old Comparator ====================
1
2
c2
csdn
db
infoworld
================= Use Lambda ====================
infoworld
db
csdn
c2
2
1
=====================================
1
2
c2
csdn
db
infoworld
Lambda instead of anonymous Runnable
=====================================
db
c2
1
2
csdn
infoworld
=====================================
infoworld
infoworld-1253667748
================== testLambda2 ===================
Tobey->
=====================================
123
================== testLambda3 ===================
Tobey->TestLambda

最后, 想查看Java8新特性和增强, 请移步 学院 JDK8-Java8-JavaSE8新特性和增强功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白行微

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值