Course Content
Stream API
Stream API
Function: Data Transformation
While Predicate
helps us evaluate boolean expressions, Function
allows us to transform data by applying operations that return results based on the input.
Function
is commonly used for data transformation, such as type conversion, calculations, or value processing.
The Function<T, R>
interface in Java represents a functional interface that takes an argument of type T
and returns a result of type R
.
The apply(T t)
method performs the data transformation by taking the input value and returning the result. This allows for creating flexible functions to process data of various types.
Practical Application
Let's say you have a list of user names, and you need to calculate the length of each name for further analysis or data processing.
Main
package com.example; import java.util.Arrays; import java.util.List; import java.util.function.Function; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Alice", "Bob", "Charlie", "David"); Function<String, Integer> nameLength = name -> name.length(); users.forEach(user -> { System.out.println(user + " has " + nameLength.apply(user) + " characters."); }); } }
In this example, you have a list of user names. For each name, you use the nameLength
function, which calculates the number of characters in the name using the length()
method. Using the forEach
method, you iterate over each element of the list and print a message showing how many characters each name contains.
Combining Functions
The Function
interface provides several methods for combining functions, allowing you to create a chain of operations.
Method andThen()
The andThen()
method allows you to combine two functions by applying one function first, then passing the result to the second function. This is useful when you need to perform multiple operations in sequence.
Example
You have a list of user names, and you need to capitalize the first letter of each name and then check if the name has more than 5 characters.
Main
package com.example; import java.util.Arrays; import java.util.List; import java.util.function.Function; public class Main { public static void main(String[] args) { List<String> usernames = Arrays.asList("john", "alice", "bob", "charlie", "david"); // Capitalize first letter Function<String, String> capitalizeFirstLetter = name -> name.substring(0, 1).toUpperCase() + name.substring(1); // Check if the username has more than 5 characters Function<String, Boolean> isLongerThanFive = name -> name.length() > 5; // Combine functions using `andThen()` Function<String, Boolean> formattedNameThenCheckLength = capitalizeFirstLetter.andThen(isLongerThanFive); usernames.forEach(user -> { System.out.println(user + " -> " + formattedNameThenCheckLength.apply(user)); }); } }
You first capitalize the first letter of each username using capitalizeFirstLetter
. Then, you check if the formatted username has more than 5 characters using isLongerThanFive
. The two functions are combined using andThen()
for sequential processing.
Method compose()
The compose()
method allows you to combine functions, but in the reverse order: the second function is applied first, and the result is then passed into the first function.
Example
You have a string, and you want to first calculate its length and then prepend a prefix to the result.
Main
package com.example; import java.util.function.Function; public class Main { public static void main(String[] args) { String phrase = "Hello World"; // First, calculate the length, then add a prefix Function<String, Integer> stringLength = String::length; Function<Integer, String> addPrefix = length -> "Length: " + length; // Combine functions using compose Function<String, String> lengthThenPrefix = addPrefix.compose(stringLength); System.out.println(lengthThenPrefix.apply(phrase)); // Output: Length: 11 } }
In this example, you first calculate the length of the string using stringLength
, and then the result is passed to the addPrefix
function, which prepends a prefix. You use compose()
to apply the functions in the desired order.
Method identity()
The identity()
method returns a function that simply returns its argument without any modifications. This is useful when you need to pass a function that doesn't change the input value but is required to comply with the interface.
Example
Imagine you need to process a list of usernames by applying several transformations: one to convert the names to uppercase, another to add the "User" suffix, and a third using the identity()
function to leave the name unchanged. The task is to apply these functions to each name in the list while keeping the program's interface consistent for each transformation.
Main
package com.example; import java.util.List; import java.util.Arrays; import java.util.function.Function; public class Main { public static void main(String[] args) { List<String> usernames = Arrays.asList("alice", "bob", "charlie", "david", "eve"); // `Function` to convert the username to uppercase Function<String, String> uppercaseFunction = name -> name.toUpperCase(); // `Function` to add the "User" suffix Function<String, String> suffixFunction = name -> name + "User"; // Identity `Function`, which does nothing Function<String, String> identityFunction = Function.identity(); // Applying a combination of functions List<Function<String, ?>> transformations = Arrays.asList(uppercaseFunction, suffixFunction, identityFunction); // Applying each `Function` from the list for (Function<String, ?> transformation : transformations) { System.out.println("--------------------"); usernames.stream() .map(name -> transformation.apply(name)) .forEach(System.out::println); } } }
As you can see, the output consists of three formatted lists of usernames. The last list contains the original names, which is where the identity()
method comes in handy, as it allows us to return the names without adding extra logic for handling the unchanged values. This makes the code cleaner and more efficient by directly using identity()
when no transformation is needed.
1. What does the andThen()
method in the Function
interface do?
2. What will be the result when applying the identity()
method?
3. What does the compose()
method do?
Thanks for your feedback!