ZetCode

Java Supplier 接口

最后修改时间:2025 年 4 月 16 日

java.util.function.Supplier 接口表示结果的提供者。它是一个函数式接口,只有一个抽象方法 get。Supplier 不接受任何参数,但会生成一个值。

Supplier 是 Java 8 中添加的 Java 函数式编程实用程序的一部分。它对于延迟求值、对象创建和值生成场景非常有用。该接口经常与 Optional 和 Streams 一起使用。

Supplier 接口概述

Supplier 接口包含一个抽象方法,没有默认方法。关键方法 get 返回结果,不接受任何输入参数。它是一个纯粹的值生成器。

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

以上代码展示了 Supplier 接口的简单结构。它使用泛型,其中 T 是提供结果的类型。该接口使用 @FunctionalInterface 进行注解,以指示其单一抽象方法。

Supplier 的基本用法

使用 Supplier 的最简单方法是使用 lambda 表达式。我们在 get 方法中定义如何生成值。此示例提供随机数。

Main.java
package com.zetcode;

import java.util.function.Supplier;
import java.util.Random;

public class Main {

    public static void main(String[] args) {

        // Define a supplier for random numbers
        Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
        
        // Get values from supplier
        System.out.println("Random 1: " + randomSupplier.get());
        System.out.println("Random 2: " + randomSupplier.get());
        
        // Supplier for current timestamp
        Supplier<Long> timeSupplier = System::currentTimeMillis;
        System.out.println("Current time: " + timeSupplier.get());
    }
}

此示例演示了 Supplier 与 lambda 和方法引用的基本用法。randomSupplier 在调用 get() 时生成随机整数。timeSupplier 使用方法引用来提供当前时间戳。

用于对象创建的 Supplier

Supplier 经常用于对象创建,尤其是在您需要延迟实例化或按需创建对象时。这使得延迟求值成为可能。

Main.java
package com.zetcode;

import java.util.function.Supplier;

class Product {
    private String name;
    private double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
        System.out.println("Creating product: " + name);
    }
    
    @Override
    public String toString() {
        return name + " ($" + price + ")";
    }
}

public class Main {

    public static void main(String[] args) {

        // Supplier for product creation
        Supplier<Product> productSupplier = () -> new Product("Laptop", 999.99);
        
        System.out.println("Supplier defined, but product not created yet");
        
        // Only creates product when get() is called
        Product p1 = productSupplier.get();
        Product p2 = productSupplier.get();
        
        System.out.println("Products created: " + p1 + ", " + p2);
    }
}

此示例显示了用于延迟对象创建的 Supplier。Product 对象仅在调用 get() 时才被实例化。这演示了使用 Supplier 的延迟初始化模式。

带有 Optional 的 Supplier

Supplier 经常与 Optional 的 orElseGet 方法一起使用,仅在需要时提供回退值。当回退创建成本较高时,这比 orElse 更有效。

Main.java
package com.zetcode;

import java.util.Optional;
import java.util.function.Supplier;

public class Main {

    public static void main(String[] args) {

        Optional<String> emptyOptional = Optional.empty();
        Optional<String> presentOptional = Optional.of("Hello");
        
        // Expensive fallback operation
        Supplier<String> fallbackSupplier = () -> {
            System.out.println("Creating fallback value");
            return "Default Value";
        };
        
        // orElseGet uses Supplier (lazy)
        String value1 = emptyOptional.orElseGet(fallbackSupplier);
        String value2 = presentOptional.orElseGet(fallbackSupplier);
        
        System.out.println("Value 1: " + value1);
        System.out.println("Value 2: " + value2);
        
        // Compare with orElse (eager)
        String value3 = emptyOptional.orElse(fallbackSupplier.get());
    }
}

此示例演示了带有 Optional 的 Supplier。fallbackSupplier 仅在 Optional 为空时执行。当回退创建成本较高时,使用 orElseGet 与 Supplier 比 orElse 更有效。

在 Stream.generate() 中使用 Supplier

Stream.generate() 方法接受一个 Supplier 来创建无限流。这对于生成值序列非常有用,其中每个值都由 Supplier 产生。

Main.java
package com.zetcode;

import java.util.stream.Stream;
import java.util.function.Supplier;
import java.util.concurrent.ThreadLocalRandom;
import java.util.List;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        // Supplier for random doubles between 0 and 1
        Supplier<Double> randomSupplier = 
            () -> ThreadLocalRandom.current().nextDouble();
        
        // Generate infinite stream of random numbers
        List<Double> randoms = Stream.generate(randomSupplier)
            .limit(5)
            .collect(Collectors.toList());
            
        System.out.println("Random numbers: " + randoms);
        
        // Supplier for sequence numbers
        Supplier<Integer> sequenceSupplier = new Supplier<>() {
            private int next = 0;
            
            @Override
            public Integer get() {
                return next++;
            }
        };
        
        List<Integer> sequence = Stream.generate(sequenceSupplier)
            .limit(5)
            .collect(Collectors.toList());
            
        System.out.println("Sequence: " + sequence);
    }
}

此示例显示了与 Stream.generate() 一起使用的 Supplier。randomSupplier 生成随机数,而 sequenceSupplier 维护状态以生成序列。两者都演示了无限流生成功能。

使用 Supplier 进行记忆化

Supplier 可用于实现记忆化——缓存昂贵计算的结果并在后续调用中返回它。此模式优化了性能。

Main.java
package com.zetcode;

import java.util.function.Supplier;

public class Main {

    public static void main(String[] args) {

        // Expensive computation simulation
        Supplier<String> expensiveSupplier = () -> {
            System.out.println("Performing expensive computation...");
            try {
                Thread.sleep(1000); // Simulate work
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Computed Result";
        };
        
        // Memoizing supplier
        Supplier<String> memoizedSupplier = new Supplier<>() {
            private String value;
            
            @Override
            public String get() {
                if (value == null) {
                    value = expensiveSupplier.get();
                }
                return value;
            }
        };
        
        System.out.println("First call (computes): " + memoizedSupplier.get());
        System.out.println("Second call (cached): " + memoizedSupplier.get());
    }
}

此示例演示了使用 Supplier 进行记忆化。昂贵的计算仅在第一次 get() 调用时发生。后续调用返回缓存值。此模式对于产生相同结果的昂贵操作非常有用。

专用 Supplier

Java 为原始类型提供了专用的 Supplier 变体,以避免装箱开销。这些包括 BooleanSupplier、IntSupplier、LongSupplier 和 DoubleSupplier。

Main.java
package com.zetcode;

import java.util.function.*;

public class Main {

    public static void main(String[] args) {

        // BooleanSupplier example
        BooleanSupplier booleanSupplier = () -> Math.random() > 0.5;
        System.out.println("Random boolean: " + booleanSupplier.getAsBoolean());
        
        // IntSupplier example
        IntSupplier intSupplier = () -> (int) (Math.random() * 100);
        System.out.println("Random int: " + intSupplier.getAsInt());
        
        // LongSupplier example
        LongSupplier longSupplier = System::currentTimeMillis;
        System.out.println("Current time: " + longSupplier.getAsLong());
        
        // DoubleSupplier example
        DoubleSupplier doubleSupplier = Math::random;
        System.out.println("Random double: " + doubleSupplier.getAsDouble());
    }
}

此示例显示了专用的 Supplier 接口。每个接口都避免了其原始类型的装箱开销。它们遵循与通用 Supplier 相同的模式,但具有特定于类型的 get 方法(getAsBoolean、getAsInt 等)。

来源

Java Supplier 接口文档

在本文中,我们介绍了 Java Supplier 接口的基本方法和功能。理解这些概念对于 Java 应用程序中的函数式编程和高效的值生成至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员。我从 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程