Java基础 - 从匿名内部类到Lambda表达式再到方法引用

如题

在当初学习Lambda表达式时,总是迷迷糊糊,恍恍惚惚,所以这次打算一次把自己讲明白。

内部类

为什么会有内部类?

场景:如果一个类只在另一个类中使用,并且需要直接访问外部类的成员,(包括私有成员),而不需要通过 gettersetter 方法。

例如Node 类通常只在 LinkedList 类中使用。

一些好处:

  • 实现多重继承
    • Java本身不支持多重继承,但是可以在类中创建多个内部类,继承不同的类

匿名内部类

  • 没有显式的类名,直接通过 new 关键字创建对象并实现接口或继承类。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Outer {
    void display() {
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello from anonymous class!");
            }
        };
        greeting.greet();
    }
}

场景

比如有一个接口Greeting,里面有一个方法greet,我想使用这个方法。

  • 传统做法:
    • 先创建一个类GreetingImpl实现这个接口,并实现接口中的greet方法,再创建这个实现类的对象,再通过对象调用这个方法。
  • 匿名内部类:
    • 实际上整个功能,有效的代码仅仅是重写我需要调用的方法这部分
    • 可以用匿名内部类直接不实现接口,直接创建一个匿名内部类实现重写我想要调用的方法
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
interface Greeting {
    void greet();
}

class GreetingImpl implements Greeting {
    @Override
    void greet(){
        System.out.println("Hello from anonymous class!");
    }
}

public class AnonymousClassExample {
    public static void main(String[] args) {
        // 传统做法
        GreetingImpl greetingImpl = new GreetingImpl();
        greetingImpl.greet();
        
        // 创建匿名内部类并实现 Greeting 接口
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello from anonymous class!");
            }
        };

        // 调用方法
        greeting.greet();
    }
}

Lambda表达式

进一步的,如果是函数式接口(即只有一个抽象方法的接口),可以用Lambda表达式代替

Lambda 表达式只能用于实现函数式接口(只有一个抽象方法的接口)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
interface Greeting {
    void greet();
}

class GreetingImpl implements Greeting {
    @Override
    void greet(){
        System.out.println("Hello from anonymous class!");
    }
}

public class AnonymousClassExample {
    public static void main(String[] args) {
        // 传统做法
        GreetingImpl greetingImpl = new GreetingImpl();
        greetingImpl.greet();
        
        // 创建匿名内部类并实现 Greeting 接口
        Greeting greeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello from anonymous class!");
            }
        };
        
        // 使用 Lambda 表达式实现接口
        Greeting greeting = () -> System.out.println("Hello from Lambda!");

        // 调用方法
        greeting.greet();
    }
}

Lambda表达式还可以用作函数式编程,“传递函数”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Calculator {
    int calculate(int a, int b);
}

public class Example {
    public static int operate(int a, int b, Calculator calculator) {
        return calculator.calculate(a, b);
    }
    
    public static void main(String[] args){
        // 传统调用,需要传递Calculator的实现类的对象,这里用匿名内部类代替
        int sum = operate(3, 5, new Calculator() {
            @Override
            public int calculate(int x, int y) {
                return x + y;
            }
        });
        
        // Lambda表达式,看似是传递了一个方法,但是实际上是传递的接口的实现类对象
        int sum = operate(3, 5, (x, y) -> x + y);
        
    }
    
}

方法引用

方法引用是简化Lambda表达式,看似是传递的方法,实际上和Lambda表达式一样传递的是接口实现类的对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MethodReferenceExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");

        // 使用 Lambda 表达式
        List<Integer> lengths1 = fruits.stream()
                                     .map(s -> s.length())
                                     .collect(Collectors.toList());
        System.out.println(lengths1); // 输出 [5, 6, 6]

        // 使用方法引用
        List<Integer> lengths2 = fruits.stream()
                                     .map(String::length)
                                     .collect(Collectors.toList());
        System.out.println(lengths2); // 输出 [5, 6, 6]
    }
}