Java Consumer Interface
Last modified: April 16, 2025
The java.util.function.Consumer
interface represents an operation
that accepts a single input argument and returns no result. It is a functional
interface with a single abstract method accept
. Consumer is used
for side-effect operations like printing or modifying objects.
Consumer
is part of Java's functional programming utilities added
in Java 8. Unlike most functional interfaces, Consumer operations are meant to
produce side effects. The interface provides default methods for consumer
chaining.
Consumer Interface Overview
Consumer
interface contains one abstract method and one default
method. The key method accept
performs the operation on the input.
The andThen
method enables consumer chaining.
@FunctionalInterface public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after); }
The code above shows the structure of Consumer
interface. It uses
generics where T is the input type. The interface is annotated with
@FunctionalInterface to indicate its single abstract method nature.
Basic Consumer Usage
The simplest way to use Consumer is with lambda expressions. We define what to do with the input in the accept method. The example prints strings to console.
package com.zetcode; import java.util.function.Consumer; public class Main { public static void main(String[] args) { // Define a consumer that prints strings Consumer<String> printer = s -> System.out.println(s); // Use the consumer printer.accept("Hello, Consumer!"); // Consumer using method reference Consumer<String> methodRefPrinter = System.out::println; methodRefPrinter.accept("Method reference consumer"); } }
This example demonstrates basic Consumer usage with lambda and method reference. The printer consumer takes a String and prints it. Method reference provides more concise syntax for existing methods that match Consumer's signature.
Consumer with Collections
Consumer is commonly used with collections through the forEach
method. This enables clean iteration patterns without explicit loops. The
example processes a list of numbers.
package com.zetcode; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // Consumer to print numbers with prefix Consumer<Integer> numberPrinter = n -> System.out.println("Number: " + n); // Apply consumer to each element numbers.forEach(numberPrinter); // Inline consumer numbers.forEach(n -> System.out.println(n * 2)); } }
This example shows Consumer usage with collections. We define a number printer consumer and pass it to forEach. The second forEach demonstrates an inline consumer. Both approaches process each collection element.
Consumer Chaining with andThen
The andThen
method allows chaining consumers where each consumer
processes the same input in sequence. This enables creating complex processing
pipelines from simple consumers.
package com.zetcode; import java.util.function.Consumer; public class Main { public static void main(String[] args) { // First consumer logs the message Consumer<String> logger = s -> System.out.println("LOG: " + s); // Second consumer sends email notification Consumer<String> notifier = s -> System.out.println("Sending notification: " + s); // Chain the consumers Consumer<String> processor = logger.andThen(notifier); // Process a message processor.accept("System started successfully"); } }
This example shows consumer chaining with andThen
. The input
message first gets logged, then triggers a notification. Both consumers
receive the same input. The order of execution is guaranteed.
Modifying Objects with Consumer
Consumers are often used to modify object state. Since they accept arguments but return nothing, they're perfect for mutating operations. The example updates product prices.
package com.zetcode; import java.util.function.Consumer; 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) { Product laptop = new Product("Laptop", 999.99); // Consumer to apply discount Consumer<Product> discount = p -> p.price = p.price * 0.9; // 10% discount System.out.println("Before: " + laptop); discount.accept(laptop); System.out.println("After: " + laptop); } }
This example demonstrates object modification with Consumer. The discount consumer takes a Product and reduces its price by 10%. Consumers are ideal for such state-changing operations while keeping code clean.
BiConsumer Interface
While Consumer takes one argument, BiConsumer
handles two inputs.
It's useful when operations need two parameters. The example processes key-value
pairs.
package com.zetcode; import java.util.function.BiConsumer; import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<String, Integer> ages = new HashMap<>(); ages.put("John", 25); ages.put("Jane", 30); ages.put("Bob", 35); // BiConsumer to print key-value pairs BiConsumer<String, Integer> agePrinter = (name, age) -> System.out.println(name + " is " + age + " years old"); // Process each map entry ages.forEach(agePrinter); // Inline BiConsumer ages.forEach((k, v) -> System.out.println(k + ": " + v)); } }
This example shows BiConsumer
usage. The agePrinter takes both
map key and value. Map's forEach expects a BiConsumer. We demonstrate both
named and inline BiConsumer variants.
Specialized Consumers
Java provides specialized Consumer interfaces for primitive types to avoid
boxing overhead. These include IntConsumer
, DoubleConsumer
,
and LongConsumer
. The example uses primitive consumers.
package com.zetcode; import java.util.function.IntConsumer; import java.util.function.DoubleConsumer; import java.util.Arrays; public class Main { public static void main(String[] args) { int[] integers = {1, 2, 3, 4, 5}; double[] doubles = {1.1, 2.2, 3.3, 4.4, 5.5}; // IntConsumer example IntConsumer squarePrinter = i -> System.out.println(i + " squared is " + (i * i)); Arrays.stream(integers).forEach(squarePrinter); // DoubleConsumer example DoubleConsumer rounder = d -> System.out.println(d + " rounded is " + Math.round(d)); Arrays.stream(doubles).forEach(rounder); } }
This example demonstrates primitive-specialized consumers. IntConsumer processes int values without boxing. DoubleConsumer handles double values. These specializations improve performance for primitive-heavy operations.
Source
Java Consumer Interface Documentation
In this article, we've covered the essential methods and features of the Java Consumer interface. Understanding these concepts is crucial for functional programming and collection processing in modern Java applications.
Author
List all Java tutorials.