Function
A Function is a functional interface in Java that represents an operation which accepts one input value and produces one output value. It is especially useful when you want to transform data from one form into another.
Think of a Function as a small transformation machine: you give it something, it processes that value, and it gives you a result. Converting a name to uppercase, calculating a price with tax, extracting a student's marks, or converting an object into a string are all examples of functional transformations.
What Is Function?
The Function<T, R> interface belongs to the java.util.function package.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
The two generic types are important. T represents the input type, while R represents the result type.
Remember: Function takes one input and produces one output. Its primary method is apply().
Basic Function Example
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function<String, Integer> length =
text -> text.length();
System.out.println(length.apply("Java"));
}
}
The Function accepts a String and returns an Integer. The input type is String, while the output type is Integer.
Understanding Function<T, R>
| Generic Type | Meaning |
|---|---|
| T | Type of input value |
| R | Type of returned result |
For example, Function<String, Integer> means the Function accepts a String and returns an Integer.
Function with the Same Input and Output Type
The input and output types do not have to be different. A Function can also accept and return the same type.
Function<String, String> upperCase =
text -> text.toUpperCase();
System.out.println(
upperCase.apply("java programming")
);
The Function receives a String and returns another String containing the transformed value.
Function with Numbers
Function<Integer, Integer> square =
number -> number * number;
System.out.println(square.apply(8));
The input and output are both Integer values, but the Function changes the input by calculating its square.
Function with Different Types
One of the biggest advantages of Function is that the input and output can have completely different types.
Function<String, Integer> convert =
text -> Integer.parseInt(text);
System.out.println(convert.apply("500"));
The string "500" enters the Function and an Integer value 500 comes out.
Function with Custom Objects
Functions are very useful when extracting information from domain objects.
import java.util.function.Function;
class Student {
String name;
int marks;
Student(String name, int marks) {
this.name = name;
this.marks = marks;
}
}
public class Main {
public static void main(String[] args) {
Function<Student, Integer> getMarks =
student -> student.marks;
Student student =
new Student("Ravi", 85);
System.out.println(
getMarks.apply(student)
);
}
}
The Function receives a Student object and extracts only its marks. This is a common pattern when working with collections and streams.
Function as a Method Parameter
A method can accept a Function as an argument, allowing the caller to decide how the input should be transformed.
import java.util.function.Function;
public class Main {
static void process(
String value,
Function<String, String> transformer) {
String result = transformer.apply(value);
System.out.println(result);
}
public static void main(String[] args) {
process(
"java",
text -> text.toUpperCase()
);
}
}
The method is not tied to one particular transformation. A different Function can be supplied whenever different behavior is required.
Function with Collections
Function becomes especially powerful with Java Streams. The map() operation commonly accepts a Function to transform every element.
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> names = Arrays.asList(
"Ravi",
"Anita",
"Priya"
);
names.stream()
.map(name -> name.toUpperCase())
.forEach(System.out::println);
}
}
The map() operation applies the Function to every element and produces a new stream containing the transformed values.
Storing a Function in a Variable
Function<Integer, Integer> doubleValue =
number -> number * 2;
System.out.println(doubleValue.apply(10));
System.out.println(doubleValue.apply(25));
The same transformation can now be reused with different input values.
Function Composition
One of the most powerful features of Function is composition. You can connect multiple Functions so that the output of one becomes the input of another.
Java provides three important methods for this purpose: andThen(), compose(), and identity().
Function andThen()
The andThen() method executes the current Function first and then passes its result to another Function.
Function<Integer, Integer> doubleValue =
number -> number * 2;
Function<Integer, Integer> addTen =
number -> number + 10;
Function<Integer, Integer> result =
doubleValue.andThen(addTen);
System.out.println(result.apply(5));
For the input 5, the first Function produces 10. The second Function then adds 10, producing 20.
Function compose()
The compose() method reverses the execution order compared with andThen(). The supplied Function executes first.
Function<Integer, Integer> doubleValue =
number -> number * 2;
Function<Integer, Integer> addTen =
number -> number + 10;
Function<Integer, Integer> result =
doubleValue.compose(addTen);
System.out.println(result.apply(5));
Here, addTen executes first: 5 becomes 15. Then doubleValue executes: 15 becomes 30.
| Method | Execution Order |
|---|---|
| andThen() | Current Function → supplied Function |
| compose() | Supplied Function → current Function |
Function identity()
The static identity() method returns a Function that simply returns its input unchanged.
Function<String, String> identity =
Function.identity();
System.out.println(
identity.apply("Java")
);
The input string is returned exactly as it was received.
Practical Example: Price Calculation
Function<Double, Double> addTax =
price -> price * 1.18;
double finalPrice = addTax.apply(1000.0);
System.out.println(finalPrice);
The Function receives the original price and returns the price after applying an 18 percent calculation. This keeps the transformation logic separate from the code that uses it.
Practical Example: Student Grade
Function<Integer, String> grade =
marks -> {
if (marks >= 90) {
return "A";
} else if (marks >= 75) {
return "B";
} else if (marks >= 60) {
return "C";
} else {
return "D";
}
};
System.out.println(grade.apply(82));
Here, an Integer is transformed into a String. This is exactly the kind of input-to-output conversion for which Function is designed.
Function vs Predicate
The distinction becomes easy once you focus on the result. Predicate always returns a boolean, while Function can return any type.
| Feature | Predicate | Function |
|---|---|---|
| Input | One value | One value |
| Output | boolean | Any type |
| Method | test() | apply() |
| Purpose | Check a condition | Transform a value |
Function vs Consumer
| Feature | Function | Consumer |
|---|---|---|
| Input | One value | One value |
| Output | One value | None |
| Method | apply() | accept() |
| Purpose | Transform data | Perform an action |
Function vs Supplier
| Feature | Function | Supplier |
|---|---|---|
| Input | One value | None |
| Output | One value | One value |
| Method | apply() | get() |
| Purpose | Transform an input | Produce a value |
Common Beginner Mistakes
- Using test() instead of apply().
- Forgetting that Function<T, R> has separate input and output types.
- Using Function when the operation only needs to check a condition; Predicate is more appropriate in that case.
- Using Function for an operation that produces no result; Consumer is designed for that purpose.
- Confusing the execution order of andThen() and compose().
Best Practices
- Use Function when the core operation is input-to-output transformation.
- Give reusable Functions descriptive names.
- Use small Functions that perform one clear transformation.
- Use andThen() and compose() when combining transformations improves readability.
- Prefer method references when they make simple transformations clearer.
Interview Insight
Interview shortcut: Function<T, R> accepts one argument of type T and returns a result of type R through apply(). It is commonly used for transformation, mapping, and function composition.
Quick Revision
| Concept | Key Point |
|---|---|
| Function<T, R> | Transforms one input into one output |
| apply() | Executes the Function |
| T | Input type |
| R | Output type |
| andThen() | Executes the current Function before another Function |
| compose() | Executes another Function before the current Function |
| identity() | Returns the input unchanged |
Final Takeaway
Function is the functional interface to choose when one value needs to be transformed into another. Its apply() method makes it ideal for data conversion, extraction, mapping, and reusable business transformations. Once you understand the pattern "one input goes in, one transformed result comes out," Function becomes a powerful building block for Java lambdas, streams, and functional programming.
