Java has a set of primitive-specialized functional interfaces of the form:
✅ XToYFunction
These are used to convert from one primitive (or boxed) type to another efficiently — avoiding boxing and unboxing.
🔧 General Pattern
interface XToYFunction {
Y applyAsY(X value);
}
Where:
XandYare primitive types likeint,long,double- These interfaces live in
java.util.function - They are designed to work more efficiently with primitives
✅ Common _To_ Function Interfaces
| Interface | Input Type | Return Type | Example Use Case |
|---|---|---|---|
IntToLongFunction | int | long | (int x) -> (long) x * 1000L |
IntToDoubleFunction | int | double | (int x) -> Math.sqrt(x) |
LongToIntFunction | long | int | (long x) -> (int)(x % 100) |
LongToDoubleFunction | long | double | (long x) -> (double) x / 2.0 |
DoubleToIntFunction | double | int | (double d) -> (int) Math.floor(d) |
DoubleToLongFunction | double | long | (double d) -> Math.round(d) |
ToIntFunction<T> | T | int | String::length |
ToLongFunction<T> | T | long | (String s) -> s.length() * 1000L |
ToDoubleFunction<T> | T | double | (String s) -> s.length() * 0.5 |
🧠 Examples
IntToDoubleFunction sqrt = x -> Math.sqrt(x);
System.out.println(sqrt.applyAsDouble(9)); // Output: 3.0
ToIntFunction<String> length = String::length;
System.out.println(length.applyAsInt("Hello")); // Output: 5
DoubleToLongFunction round = Math::round;
System.out.println(round.applyAsLong(2.7)); // Output: 3
✅ Summary
These interfaces are:
- Efficient: avoid boxing (
Integer,Double, etc.) - Clear in intent: show exactly what’s being converted
- Useful for data transformation in streams and calculations
🎯 Why Were These Interfaces Created?
1. Performance: Avoid Autoboxing
Java generics don’t support primitives (e.g., you can’t do Function<int, int>), so when you use Function<Integer, Integer>, Java autoboxes the int to Integer — which:
- Creates temporary heap objects (
Integerinstead of rawint) - Hurts performance in tight loops or big streams
✅ Solution: Introduce primitive-specialized functional interfaces like:
IntFunction<R>,ToIntFunction<T>IntToDoubleFunction,DoubleToLongFunction
→ These work directly with primitives, no boxing involved.
2. Cleaner Code for Primitive Operations
Imagine this:
Function<Integer, Double> sqrt = x -> Math.sqrt(x);
Better
IntToDoubleFunction sqrt = x -> Math.sqrt(x);
This is faster and shows intent more clearly: I’m working with primitive int and returning a double.
3. Stream API Compatibility
When you work with primitive streams (IntStream, LongStream, DoubleStream), they require primitive functional interfaces.
For example:
IntStream.range(1, 5)
.mapToDouble(x -> Math.pow(x, 2)) // Needs IntToDoubleFunction
.forEach(System.out::println);
You can’t use Function<Integer, Double> here — it would crash or box, defeating the purpose.
📍 Where Should You Use Them?
✅ 1. In Primitive Streams (IntStream, LongStream, DoubleStream)
IntToDoubleFunction toSqrt = Math::sqrt;
IntStream.of(1, 4, 9)
.mapToDouble(toSqrt)
.forEach(System.out::println);
✅ 2. In High-performance numeric code
Anywhere you process a lot of numbers (e.g., sensor data, financial calculations, image processing), avoiding boxing matters.
DoubleToIntFunction discretizer = d -> (int)(d * 100);
✅ 3. When You Want to Be Explicit & Intentional
ToIntFunction<String> length = String::length;— very readable- Clearer than
Function<String, Integer>and faster
🧠 Summary
| Reason | Explanation |
|---|---|
| ✅ Avoid boxing | No Integer, Double heap objects — better performance |
| ✅ Work with primitive streams | Stream API requires these for IntStream, LongStream, DoubleStream |
| ✅ More readable code | Makes it clear you’re converting between primitive types |