Java UnaryOperator Interface
Last modified: April 16, 2025
The java.util.function.UnaryOperator
interface represents an operation
on a single operand that produces a result of the same type. It extends the
Function
interface and is a functional interface with method
apply
. UnaryOperator is commonly used for transformations where
input and output types match.
UnaryOperator
is part of Java's functional programming utilities
added in Java 8. It specializes Function for cases where the input and output
types are identical. This simplifies type declarations and provides type safety.
UnaryOperator Interface Overview
UnaryOperator
interface contains one abstract method inherited from
Function and several static methods. The key method apply
performs
the operation on the input. Static methods provide useful operator instances.
@FunctionalInterface public interface UnaryOperator<T> extends Function<T, T> { static <T> UnaryOperator<T> identity(); }
The code above shows the structure of UnaryOperator
interface. It
extends Function with identical input and output types. The identity method
returns a UnaryOperator that always returns its input argument.
Basic UnaryOperator Usage
The simplest way to use UnaryOperator is with lambda expressions. We define how to transform the input to output of the same type. The example squares integers.
package com.zetcode; import java.util.function.UnaryOperator; public class Main { public static void main(String[] args) { // Define a UnaryOperator that squares integers UnaryOperator<Integer> square = x -> x * x; // Apply the operator System.out.println("Square of 5: " + square.apply(5)); System.out.println("Square of 12: " + square.apply(12)); // UnaryOperator using method reference UnaryOperator<String> toUpper = String::toUpperCase; System.out.println("Uppercase: " + toUpper.apply("hello")); } }
This example demonstrates basic UnaryOperator usage with lambda and method reference. The square operator takes Integer and returns Integer. The toUpper operator transforms strings to uppercase. Both maintain input-output type.
UnaryOperator Composition
UnaryOperator inherits composition methods from Function. andThen
and compose
allow chaining operations while maintaining type
consistency. This creates powerful transformation pipelines.
package com.zetcode; import java.util.function.UnaryOperator; public class Main { public static void main(String[] args) { // First operator increments by 1 UnaryOperator<Integer> increment = x -> x + 1; // Second operator multiplies by 2 UnaryOperator<Integer> doubler = x -> x * 2; // Compose the operators UnaryOperator<Integer> incrementThenDouble = increment.andThen(doubler); UnaryOperator<Integer> doubleThenIncrement = doubler.andThen(increment); System.out.println("Increment then double 5: " + incrementThenDouble.apply(5)); System.out.println("Double then increment 5: " + doubleThenIncrement.apply(5)); } }
This example shows UnaryOperator composition. We chain mathematical operations while maintaining Integer type throughout. The order of operations affects the final result significantly.
UnaryOperator Identity
The UnaryOperator.identity
method returns an operator that always
returns its input argument unchanged. It's useful as a default or neutral
operation in transformation pipelines.
package com.zetcode; import java.util.function.UnaryOperator; public class Main { public static void main(String[] args) { // Identity operator UnaryOperator<String> identity = UnaryOperator.identity(); System.out.println("Identity applied: " + identity.apply("test")); // Practical use with optional transformation UnaryOperator<String> transformer = someCondition() ? String::toUpperCase : UnaryOperator.identity(); System.out.println("Result: " + transformer.apply("conditional")); } private static boolean someCondition() { return false; } }
This example demonstrates UnaryOperator.identity
. The identity
operator returns its input unchanged. It serves as a neutral element when
conditional transformation is needed but sometimes no operation is required.
Using UnaryOperator with Streams
UnaryOperator works naturally with Java Streams for in-place transformations. The map operation accepts a UnaryOperator when input and output types match. This enables clean data processing pipelines.
package com.zetcode; import java.util.Arrays; import java.util.List; import java.util.function.UnaryOperator; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // UnaryOperator to square numbers UnaryOperator<Integer> square = x -> x * x; // Apply operator in stream List<Integer> squaredNumbers = numbers.stream() .map(square) .collect(Collectors.toList()); System.out.println("Original: " + numbers); System.out.println("Squared: " + squaredNumbers); } }
This example shows UnaryOperator usage in Streams. We define a squaring operator and apply it to each stream element via map. The result is a new list with transformed values while maintaining the Integer type throughout.
UnaryOperator for String Manipulation
UnaryOperator is particularly useful for string transformations where the operation preserves the String type. Common examples include trimming, case conversion, and formatting.
package com.zetcode; import java.util.function.UnaryOperator; public class Main { public static void main(String[] args) { // Trim and capitalize string UnaryOperator<String> trimAndCapitalize = s -> { String trimmed = s.trim(); return trimmed.substring(0, 1).toUpperCase() + trimmed.substring(1).toLowerCase(); }; System.out.println("Formatted: " + trimAndCapitalize.apply(" hELLO ")); // Repeat string three times UnaryOperator<String> tripler = s -> s + s + s; System.out.println("Tripled: " + tripler.apply("hi")); } }
This example demonstrates String manipulation with UnaryOperator. We create operators that clean and format strings while maintaining the String type. The operators can be reused across different string processing scenarios.
Specialized UnaryOperator Variants
Java provides specialized UnaryOperator variants for primitive types to avoid
boxing overhead. These include IntUnaryOperator
,
LongUnaryOperator
, and DoubleUnaryOperator
.
package com.zetcode; import java.util.function.IntUnaryOperator; import java.util.function.DoubleUnaryOperator; public class Main { public static void main(String[] args) { // IntUnaryOperator example IntUnaryOperator negate = x -> -x; System.out.println("Negated: " + negate.applyAsInt(42)); // DoubleUnaryOperator example DoubleUnaryOperator celsiusToFahrenheit = c -> (c * 9/5) + 32; System.out.println("20°C in Fahrenheit: " + celsiusToFahrenheit.applyAsDouble(20)); } }
This example shows specialized UnaryOperator variants. IntUnaryOperator
works with int primitives directly, avoiding Integer boxing. Similarly,
DoubleUnaryOperator
handles double primitives efficiently.
Source
Java UnaryOperator Interface Documentation
In this article, we've covered the essential methods and features of the Java UnaryOperator interface. Understanding these concepts is crucial for type-safe transformations in functional programming and stream processing.
Author
List all Java tutorials.