Java BiConsumer 接口
最后修改时间:2025 年 4 月 16 日
java.util.function.BiConsumer
接口表示一个接受两个输入参数且不返回结果的操作。它是一个函数式接口,只有一个抽象方法 accept
。 BiConsumer 用于需要处理两个值而不返回任何内容的操作。
BiConsumer
是 Java 8 中新增的 Java 函数式编程工具的一部分。它允许对两个输入参数执行副作用操作。常见用途包括迭代地图或对值对执行操作。
BiConsumer 接口概述
BiConsumer
接口包含一个抽象方法和一个默认方法。 关键方法 accept
对输入执行操作。 andThen
方法允许链接多个 BiConsumer。
@FunctionalInterface public interface BiConsumer<T, U> { void accept(T t, U u); default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after); }
上面的代码显示了 BiConsumer
接口的结构。它使用泛型,其中 T 和 U 是输入类型。 接口使用 @FunctionalInterface 注解,以表明其单抽象方法的性质。
BiConsumer 的基本用法
使用 BiConsumer 的最简单方法是使用 lambda 表达式。我们定义如何在 accept 方法中处理两个输入值。 此示例打印键值对。
package com.zetcode; import java.util.function.BiConsumer; public class Main { public static void main(String[] args) { // Define a BiConsumer that prints two values BiConsumer<String, Integer> printPair = (key, value) -> System.out.println("Key: " + key + ", Value: " + value); // Use the BiConsumer printPair.accept("age", 30); printPair.accept("score", 95); // BiConsumer using method reference BiConsumer<String, String> concatPrinter = System.out::println; concatPrinter.accept("Hello", "World"); } }
此示例演示了使用 lambda 和方法引用的 BiConsumer 基本用法。 printPair 接受 String 和 Integer 输入并打印它们。 方法引用为匹配 BiConsumer 签名的现有方法提供了简洁的语法。
BiConsumer 与 Map 迭代
BiConsumer
常用于 Map 的 forEach 方法。 Map 的键值对与 BiConsumer 的两个输入参数完全匹配。 这使得可以干净地迭代 map 条目。
package com.zetcode; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; public class Main { public static void main(String[] args) { Map<String, Integer> scores = new HashMap<>(); scores.put("Alice", 85); scores.put("Bob", 92); scores.put("Charlie", 78); // BiConsumer to print map entries BiConsumer<String, Integer> printEntry = (name, score) -> System.out.println(name + ": " + score); // Iterate map with BiConsumer scores.forEach(printEntry); // Direct lambda in forEach scores.forEach((k, v) -> { if (v > 80) { System.out.println(k + " passed"); } }); } }
此示例显示了 BiConsumer 与 Map.forEach 的用法。 我们首先定义一个单独的 BiConsumer 用于打印条目,然后使用直接 lambda 进行条件逻辑。 使用 BiConsumer,Map 迭代变得非常有表现力。
使用 andThen 链接 BiConsumer
andThen
方法允许链接多个 BiConsumer 以执行顺序操作。链中的每个 BiConsumer 接收相同的输入参数。
package com.zetcode; import java.util.function.BiConsumer; public class Main { public static void main(String[] args) { // First BiConsumer logs the operation BiConsumer<String, Integer> logger = (item, qty) -> System.out.println("Processing: " + item + " x" + qty); // Second BiConsumer processes the order BiConsumer<String, Integer> processor = (item, qty) -> System.out.println("Ordered " + qty + " of " + item); // Chain the BiConsumers BiConsumer<String, Integer> orderHandler = logger.andThen(processor); // Use the chained BiConsumer orderHandler.accept("Laptop", 2); orderHandler.accept("Mouse", 5); } }
此示例演示了使用 andThen
链接 BiConsumer。 orderHandler 为每个输入对执行日志记录和处理。 链执行时,两个 BiConsumer 接收相同的参数。
BiConsumer 用于对象修改
BiConsumer
可用于根据两个输入参数修改对象属性。 这对于批量更新或配置操作很有用。
package com.zetcode; import java.util.function.BiConsumer; class Product { String name; double price; Product(String name, double price) { this.name = name; this.price = price; } @Override public String toString() { return name + ": $" + price; } } public class Main { public static void main(String[] args) { // BiConsumer to update product price with discount BiConsumer<Product, Double> applyDiscount = (product, discount) -> { product.price = product.price * (1 - discount/100); System.out.println("Applied " + discount + "% discount"); }; Product laptop = new Product("Laptop", 999.99); Product phone = new Product("Phone", 699.99); applyDiscount.accept(laptop, 10.0); applyDiscount.accept(phone, 15.0); System.out.println(laptop); System.out.println(phone); } }
此示例显示了 BiConsumer 修改对象状态。 applyDiscount BiConsumer 接受一个 Product 和折扣百分比,然后更新产品的价格。 这种模式对于应用一致的修改很有用。
BiConsumer 在流操作中
BiConsumer
可用于处理值对的流操作。虽然在流中不如 Function 常见,但它对于具有副作用的终端操作很有用。
package com.zetcode; import java.util.List; import java.util.function.BiConsumer; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<Integer> scores = List.of(85, 92, 78); // BiConsumer to print name-score pairs BiConsumer<String, Integer> printResult = (name, score) -> System.out.println(name + " scored " + score); // Process parallel lists with BiConsumer if (names.size() == scores.size()) { for (int i = 0; i < names.size(); i++) { printResult.accept(names.get(i), scores.get(i)); } } // More complex BiConsumer BiConsumer<String, Integer> resultAnalyzer = (name, score) -> { String status = score >= 80 ? "Pass" : "Fail"; System.out.println(name + ": " + score + " (" + status + ")"); }; System.out.println("\nAnalysis:"); for (int i = 0; i < names.size(); i++) { resultAnalyzer.accept(names.get(i), scores.get(i)); } } }
此示例演示了 BiConsumer 处理并行列表。我们定义了两个 BiConsumer - 一个用于简单的打印,另一个用于更复杂的分析。当在单独的集合中处理相关数据时,这种模式很有用。
BiConsumer 的基本类型特化
Java 为基本类型提供了 BiConsumer 的专门版本,以避免自动装箱开销。 这些包括 ObjIntConsumer、ObjLongConsumer 和 ObjDoubleConsumer。
package com.zetcode; import java.util.function.ObjIntConsumer; import java.util.function.ObjDoubleConsumer; public class Main { public static void main(String[] args) { // ObjIntConsumer example ObjIntConsumer<String> printWithNumber = (s, i) -> System.out.println(s + ": " + i); printWithNumber.accept("Count", 42); // ObjDoubleConsumer example ObjDoubleConsumer<String> temperatureLogger = (location, temp) -> System.out.printf("%s: %.1f°C%n", location, temp); temperatureLogger.accept("New York", 22.5); // Using BiConsumer with boxed primitives BiConsumer<String, Integer> boxedConsumer = (s, i) -> System.out.println(s.repeat(i)); boxedConsumer.accept("Hi ", 3); } }
此示例显示了 BiConsumer 的基本类型特化。 ObjIntConsumer 和 ObjDoubleConsumer 在使用基本类型时避免了装箱开销。 最后一个示例显示了带有装箱 Integer 的常规 BiConsumer 用于比较。
将 BiConsumer 与其他函数式接口结合使用
BiConsumer
可以与其他函数式接口结合使用以创建更复杂的操作。此示例展示了将其与 Function 配对以在消耗之前进行数据转换。
package com.zetcode; import java.util.function.BiConsumer; import java.util.function.Function; public class Main { public static void main(String[] args) { // Function to calculate area Function<Double, Double> areaCalculator = radius -> Math.PI * radius * radius; // BiConsumer to print formatted results BiConsumer<String, Double> resultPrinter = (label, value) -> System.out.printf("%s: %.2f%n", label, value); // Process radius values double[] radii = {1.0, 2.5, 3.0}; for (double r : radii) { double area = areaCalculator.apply(r); resultPrinter.accept("Radius " + r + " area", area); } // More complex combination BiConsumer<String, Function<Double, Double>> calculator = (name, func) -> { double result = func.apply(10.0); System.out.println(name + " at 10.0: " + result); }; calculator.accept("Square", x -> x * x); calculator.accept("Cube", x -> x * x * x); } }
此示例演示了将 BiConsumer 与 Function 结合使用。 我们首先将它们分开用于计算和打印,然后创建一个 BiConsumer,它接受一个 Function 作为其第二个参数。 这显示了函数式接口的灵活性。
来源
在本文中,我们介绍了 Java BiConsumer 接口的基本方法和特性。 理解这些概念对于现代 Java 应用程序中的函数式编程和集合处理至关重要。
作者
列出所有Java教程。