Java DoubleSupplier 接口
最后修改时间:2025 年 4 月 16 日
java.util.function.DoubleSupplier
接口代表一个提供 double 类型结果的供应器。它是一个函数式接口,只有一个抽象方法 getAsDouble
。这个接口不需要输入参数。
DoubleSupplier
是 Java 8 中添加的函数式编程实用程序的一部分。当您需要生成或提供 double 值而无需任何输入时,它非常有用。该接口通常用于惰性求值场景。
DoubleSupplier 接口概述
DoubleSupplier
接口包含一个抽象方法。关键方法 getAsDouble
返回一个 double 值。此接口中没有默认方法或静态方法。
@FunctionalInterface public interface DoubleSupplier { double getAsDouble(); }
上面的代码展示了 DoubleSupplier
的简单结构。它使用 @FunctionalInterface 注解来表明其单一抽象方法的性质。该接口专门用于原始 double 类型值。
DoubleSupplier 的基本用法
使用 DoubleSupplier 的最简单方法是使用 lambda 表达式。我们在 getAsDouble 方法中定义如何生成 double 值。示例提供随机数。
package com.zetcode; import java.util.function.DoubleSupplier; public class Main { public static void main(String[] args) { // Define a supplier that generates random numbers DoubleSupplier randomSupplier = () -> Math.random(); // Get values from the supplier System.out.println("Random 1: " + randomSupplier.getAsDouble()); System.out.println("Random 2: " + randomSupplier.getAsDouble()); // Supplier with fixed value DoubleSupplier fixedSupplier = () -> 3.1415; System.out.println("Fixed value: " + fixedSupplier.getAsDouble()); } }
此示例演示了使用 lambda 表达式的 DoubleSupplier 的基本用法。randomSupplier 每次调用时都会生成新的随机数。fixedSupplier 总是返回相同的值。供应器是惰性求值的。
使用方法引用的 DoubleSupplier
当现有方法与接口匹配时,方法引用提供了一种创建 DoubleSupplier 实例的简洁方法。这适用于不带参数并返回 double 值的方法。
package com.zetcode; import java.util.function.DoubleSupplier; public class Main { public static void main(String[] args) { // Create a supplier using method reference DoubleSupplier piSupplier = Math::PI; DoubleSupplier nanSupplier = Double::NaN; System.out.println("PI value: " + piSupplier.getAsDouble()); System.out.println("NaN value: " + nanSupplier.getAsDouble()); // Instance method reference Random random = new Random(); DoubleSupplier randomSupplier = random::nextDouble; System.out.println("Random from instance: " + randomSupplier.getAsDouble()); } }
此示例展示了通过方法引用创建 DoubleSupplier。我们使用了 Math 和 Double 类的静态方法,以及 Random 的实例方法。方法引用使代码更简洁易读。
DoubleSupplier 在流生成中
DoubleSupplier 对于生成无限的 double 值流非常有用。DoubleStream.generate
方法接受一个 DoubleSupplier 来生成流元素。这使得值的惰性生成成为可能。
package com.zetcode; import java.util.function.DoubleSupplier; import java.util.stream.DoubleStream; public class Main { public static void main(String[] args) { // Create a supplier for sequence numbers double[] counter = {0.0}; DoubleSupplier sequenceSupplier = () -> counter[0] += 1.0; // Generate stream of 5 sequence numbers DoubleStream.generate(sequenceSupplier) .limit(5) .forEach(System.out::println); // Random numbers stream DoubleStream.generate(Math::random) .limit(3) .forEach(d -> System.out.printf("Random: %.4f%n", d)); } }
此示例演示了 DoubleSupplier 在流生成中的应用。我们创建了一个递增计数器的序列供应器和一个随机数供应器。该流被限制以避免无限处理。每个元素都按需生成。
使用 DoubleSupplier 的惰性求值
DoubleSupplier 通过推迟值生成直到需要时启用惰性求值。这对于昂贵的计算或可能不使用值的情况非常有用。供应器充当一个值工厂。
package com.zetcode; import java.util.function.DoubleSupplier; public class Main { public static void main(String[] args) { // Expensive computation wrapped in supplier DoubleSupplier expensiveCalc = () -> { System.out.println("Performing expensive calculation..."); try { Thread.sleep(1000); // Simulate long computation } catch (InterruptedException e) { e.printStackTrace(); } return Math.PI * Math.E; }; System.out.println("Supplier created, but no calculation yet"); // Only calculate when actually needed if (args.length > 0) { System.out.println("Result: " + expensiveCalc.getAsDouble()); } } }
此示例展示了使用 DoubleSupplier 的惰性求值。昂贵的计算仅在调用 getAsDouble() 时执行。如果没有供应器,计算将在初始化期间立即发生。惰性求值提高了性能。
DoubleSupplier 用于配置值
DoubleSupplier 可以提供灵活的配置值。实际值可以在调用之间更改,或者在运行时确定。这对于动态配置系统非常有用。
package com.zetcode; import java.util.function.DoubleSupplier; import java.time.LocalTime; public class Main { public static void main(String[] args) { // Time-based discount factor DoubleSupplier discountSupplier = () -> { int hour = LocalTime.now().getHour(); return hour >= 20 || hour < 6 ? 0.9 : 1.0; // 10% discount at night }; System.out.println("Current discount factor: " + discountSupplier.getAsDouble()); // Environment-based configuration DoubleSupplier configSupplier = () -> "prod".equals(System.getenv("APP_ENV")) ? 1.0 : 0.5; System.out.println("Config value: " + configSupplier.getAsDouble()); } }
此示例演示了 DoubleSupplier 用于动态配置。折扣供应器根据当前时间更改值。配置供应器从环境变量读取。供应器实现了运行时值的确定。
组合 DoubleSuppliers
虽然 DoubleSupplier 没有内置的组合方法,但我们可以手动组合供应器来创建更复杂的值生成器。这允许从简单的供应器构建复杂的供应器。
package com.zetcode; import java.util.function.DoubleSupplier; public class Main { public static void main(String[] args) { // Base suppliers DoubleSupplier randomSupplier = Math::random; DoubleSupplier fixedSupplier = () -> 10.0; // Combined supplier - average of random and fixed DoubleSupplier averageSupplier = () -> (randomSupplier.getAsDouble() + fixedSupplier.getAsDouble()) / 2; System.out.println("Average value: " + averageSupplier.getAsDouble()); // Conditional supplier boolean useHighPrecision = true; DoubleSupplier precisionSupplier = useHighPrecision ? () -> Math.PI : () -> 3.14; System.out.println("PI value: " + precisionSupplier.getAsDouble()); } }
此示例展示了如何组合 DoubleSuppliers。我们创建了一个平均值供应器,它结合了另外两个供应器。我们还演示了一个条件供应器,该供应器根据标志更改行为。组合实现了灵活的值生成。
DoubleSupplier 与其他供应器的比较
Java 提供了几个针对不同类型的供应器接口。DoubleSupplier 专门用于原始 double 类型,避免了装箱开销。其他供应器如 Supplier<Double> 适用于包装对象。
package com.zetcode; import java.util.function.DoubleSupplier; import java.util.function.Supplier; public class Main { public static void main(String[] args) { // Primitive double supplier DoubleSupplier primitiveSupplier = () -> Math.random(); // Wrapper Double supplier Supplier<Double> wrapperSupplier = () -> Math.random(); System.out.println("Primitive: " + primitiveSupplier.getAsDouble()); System.out.println("Wrapper: " + wrapperSupplier.get()); // Performance consideration long start = System.nanoTime(); for (int i = 0; i < 1_000_000; i++) { primitiveSupplier.getAsDouble(); } System.out.println("Primitive time: " + (System.nanoTime() - start)/1_000_000 + " ms"); start = System.nanoTime(); for (int i = 0; i < 1_000_000; i++) { wrapperSupplier.get(); } System.out.println("Wrapper time: " + (System.nanoTime() - start)/1_000_000 + " ms"); } }
此示例将 DoubleSupplier 与 Supplier<Double> 进行了比较。原始版本避免了装箱开销,对于密集的数值运算更有效。当使用通用 API 时,需要包装器版本。
来源
在本文中,我们介绍了 Java DoubleSupplier 接口的基本方法和特性。理解这些概念对于函数式编程和 Java 应用程序中的高效数值运算至关重要。
作者
列出所有Java教程。