Java 函数式编程(Lambda)

jdk8开始新增

函数式编程: 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好


7.1 Lambda函数简介

可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好

复制代码
(被重写方法的形参列表) -> {
      被重写方法的方法体代码  
}

注意 : Lambda表达式只能替代函数式接口的匿名内部类!

!什么是函数式接口?

有且仅有一个抽象方法的接口

注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,该注解用于约束当前接口必须是函数式接口

示例:

java 复制代码
// 1. 定义一个函数式接口(有且仅有一个抽象方法)
@FunctionalInterface
interface Calculator {
    int add(int a, int b);
}

public class LambdaBasicDemo {
    public static void main(String[] args) {
        // 【传统写法】匿名内部类
        Calculator oldWay = new Calculator() {
            @Override
            public int add(int a, int b) {
                return a + b;
            }
        };

        // 【Lambda写法】简洁明了
        Calculator lambdaWay = (int a, int b) -> {
            return a + b;
        };

        System.out.println(lambdaWay.add(3, 5)); // 输出: 8
    }
}

7.2 Lambda表达式的省略规则

作用:用于进一步简化Lambda表达式的写法

具体规则:

  1. 参数类型全部可以省略不写
  2. 如果只有一个参数,参数类型省略的同时"()"也可以省略,但多个参数不能省略"()"
  3. 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号";"如果这行代码是return语句,也必须去掉return

示例:

java 复制代码
import java.util.Arrays;
import java.util.List;

public class LambdaOmissionDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");

        // 【完整写法】
        // names.forEach((String name) -> { System.out.println(name); });

        // 【省略规则演示】
        // 1. 省略参数类型 String
        // 2. 只有一个参数,省略小括号 ()
        // 3. 只有一行代码,省略大括号 {}、分号 ; 
        names.forEach(name -> System.out.println(name));
    }
}

7.3 方法引用

进一步简化 Lambda 表达式

以下4中特定场景才能用方法引用

7.3.1 静态方法引用

格式:类名::静态方法

使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且"→"前后参数的形式一致,就可以使用静态方法引用

示例:

java 复制代码
import java.util.Arrays;
import java.util.List;

public class StaticMethodRefDemo {
    // 自定义静态方法,参数与Consumer.accept(T)一致
    public static void printUpperCase(String s) {
        System.out.println(s.toUpperCase());
    }

    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "world");

        // Lambda写法: list.forEach(s -> StaticMethodRefDemo.printUpperCase(s));
        // 静态方法引用: 前后参数形式一致,直接引用
        list.forEach(StaticMethodRefDemo::printUpperCase);
    }
}
7.3.2 实例方法引用

格式:对象名::实例方法

使用场景:如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且"→"前后参数的形式一致,就可以使用实例方法引用

示例:

java 复制代码
import java.util.Arrays;
import java.util.List;

public class InstanceMethodRefDemo {
    public void printWithPrefix(String s) {
        System.out.println(">> " + s);
    }

    public static void main(String[] args) {
        InstanceMethodRefDemo obj = new InstanceMethodRefDemo();
        List<String> list = Arrays.asList("Java", "Lambda");

        // Lambda写法: list.forEach(s -> obj.printWithPrefix(s));
        // 实例方法引用: 通过已有对象调用实例方法
        list.forEach(obj::printWithPrefix);
    }
}
7.3.3 特定类的方法引用

格式:特定类的名称::方法

使用场景:如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用

示例:

java 复制代码
import java.util.Arrays;
import java.util.List;

public class ClassMethodRefDemo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hello", "WORLD", "Java");

        // Lambda写法: list.forEach(s -> s.toLowerCase())
        // 这里 s 是第一个参数,同时也是 toLowerCase() 的调用者
        // 符合"特定类的方法引用"场景
        list.forEach(String::toLowerCase); 
        
        // 注意:上面这行只是演示语法,实际forEach需要Consumer
        // 更常见的实际使用场景是在Stream中:
        list.stream()
            .map(String::toUpperCase)  // s -> s.toUpperCase()
            .forEach(System.out::println);
    }
}
7.3.4 构造器引用

格式:类名::new

使用场景:如果某个Lambda表达式里只是在创建对象,并且"→"前后参数情况一致,就可以使用构造器引用

示例:

java 复制代码
import java.util.function.Function;
import java.util.function.Supplier;

class User {
    private String name;
    
    // 无参构造
    public User() { this.name = "Default"; }
    
    // 有参构造
    public User(String name) { this.name = name; }
    
    @Override
    public String toString() { return "User{name='" + name + "'}"; }
}

public class ConstructorRefDemo {
    public static void main(String[] args) {
        // 【无参构造器引用】 对应 Supplier<User>
        // Lambda: () -> new User()
        Supplier<User> userSupplier = User::new;
        System.out.println(userSupplier.get()); // User{name='Default'}

        // 【有参构造器引用】 对应 Function<String, User>
        // Lambda: name -> new User(name)
        Function<String, User> userFunction = User::new;
        System.out.println(userFunction.apply("张三")); // User{name='张三'}
    }
}

相关推荐
rannn_1112 小时前
【力扣hot100】链表专题下|138、148、23、146
java·算法·leetcode·链表·开发
lv__pf2 小时前
Spring配置类解析 【TL spring 11】
java·前端·spring
xzlAwin2 小时前
Win10安装Go语言多版本管理器g工具
开发语言·golang
(initial)2 小时前
C-05. Kernel Fusion 代价边界:少写回 vs 寄存器压力与 occupancy
c语言·开发语言·cuda
zhougl9962 小时前
Java Spring Boot 爬虫技术全面介绍
java·spring boot·爬虫
奥莱维2 小时前
【无标题】
java·前端·javascript
汤姆yu3 小时前
基于python大数据的高校舆情监测系统的设计与实现
大数据·开发语言·python·分享·分析·舆情
Cory.眼3 小时前
Python爬虫实战:从入门到进阶
开发语言·爬虫·python
风流 少年3 小时前
Spring AI 2.0:Hello World
java·人工智能·spring