Definition
- UnaryOperator
extends Functionwith identical input and output types. - Ideal for type-preserving transformations: normalise, trim, lowercase, encrypt.
- List.replaceAll(UnaryOperator) rewrites each element in place.
- Inherits andThen and compose from Function for chaining.
- Prefer strip() (Java 11, Unicode-aware) over trim() for modern code.
Priya at the National Bank of India tidies up messy names: strips the extra spaces and makes everything lowercase so the records are consistent. Same thing in, cleaned-up same thing out.
Understanding the Concepts
How do you write a UnaryOperator for name normalisation?
UnaryOperator extends Function with both type parameters equal.
package com.bank.hr;
import java.util.*;
import java.util.function.UnaryOperator;
public class NormaliseName {
public static void main(String[] args) {
UnaryOperator<String> normalise = s -> s.strip().toLowerCase();
List<String> names = new ArrayList<>(List.of(
" Rajesh ", "PRIYA", " amit "));
names.replaceAll(normalise);
System.out.println(names);
}
}
[rajesh, priya, amit]
Why use UnaryOperator instead of Function?
UnaryOperator signals intent: the operation preserves the type. APIs like List.replaceAll specifically require UnaryOperator, not Function.
| Type | Signature | Use case | |---|---|---| | UnaryOperator<T> | T -> T | Type-preserving: normalise, encrypt | | Function<T, R> | T -> R | Type-changing: Employee -> String |
How do you chain normalisation steps?
Because UnaryOperator is a Function, it supports andThen and compose.
UnaryOperator<String> stripOp = String::strip;
UnaryOperator<String> lowerOp = String::toLowerCase;
// Chain: strip then lowercase
UnaryOperator<String> normalise =
((UnaryOperator<String>) String::strip)
.andThen(String::toLowerCase)::apply;
// Or simply:
UnaryOperator<String> simple = s -> s.strip().toLowerCase();
Why prefer strip() over trim()?
| Method | Whitespace handled | Introduced | |---|---|---| | trim() | ASCII whitespace only (chars <= 0x20) | Java 1.0 | | strip() | Unicode whitespace (Character.isWhitespace) | Java 11 |
String s = "\u2003Rajesh\u2003"; // em space (Unicode)
System.out.println(s.trim()); // "\u2003Rajesh\u2003" (not trimmed!)
System.out.println(s.strip()); // "Rajesh" (trimmed correctly)
What are common mistakes?
Mistake: using different normalisation in different code paths.
// Path 1: lowercase only
String key1 = name.toLowerCase();
// Path 2: trim + lowercase
String key2 = name.strip().toLowerCase();
// These produce different keys for " Rajesh " → phantom duplicates!
// CORRECT: use the same UnaryOperator everywhere
static final UnaryOperator<String> NORMALISE = s -> s.strip().toLowerCase();
What should a senior engineer know?
- Keep normalisation in a single, well-named operator so every code path uses the same canonicalisation.
- Inconsistent normalisation causes phantom duplicates: two entries for the same person that look different.
- UnaryOperator.identity() returns the input unchanged, useful as a default.
- For streams, .map(normalise) works because UnaryOperator is a Function.
What are common interview follow-up questions?
- "What is BinaryOperator?" A specialisation of BiFunction
where all types are the same. - "Can UnaryOperator be used with mapToInt?" No; mapToInt requires ToIntFunction. Use IntUnaryOperator for primitive ints.
- "How do you normalise in a stream?" .map(normalise) applies the operator to each element.
Visual Overview
Input: " Rajesh "
│
│ strip()
▼
"Rajesh"
│
│ toLowerCase()
▼
"rajesh"
List.replaceAll(normalise):
[" Rajesh ", "PRIYA", " amit "]
│
▼
["rajesh", "priya", "amit"]
Key Takeaway
UnaryOperator
Keep the normalisation in a single named operator and reuse it everywhere names are compared or stored. At the National Bank of India, inconsistent normalisation between code paths caused phantom duplicate records; a shared UnaryOperator eliminated the problem.
Prefer strip() over trim() for Unicode-aware whitespace handling in modern Java. UnaryOperator inherits andThen and compose from Function for chaining.
Remember one sentence: UnaryOperator
---