In Java 8, BiFunction is a functional interface; it takes two arguments and returns an object.
BiFunction.java
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
- T – Type of the first argument to the function.
- U – Type of the second argument to the function.
- R – Type of the result of the function.
1. BiFunction<T, U, R>
1.1 This example takes two Integers
and returns an Integer
, Double
or List
Java8BiFunction1.java
package com.favtuts.java8; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; public class Java8BiFunction1 { public static void main(String[] args) { // takes two Integers and return an Integer BiFunction<Integer, Integer, Integer> func = (x1, x2) -> x1 + x2; Integer result = func.apply(2, 3); System.out.println(result); // 5 // take two Integers and return an Double BiFunction<Integer, Integer, Double> func2 = (x1, x2) -> Math.pow(x1, x2); Double result2 = func2.apply(2, 4); System.out.println(result2); // 16.0 // take two Integers and return a List<Integer> BiFunction<Integer, Integer, List<Integer>> func3 = (x1, x2) -> Arrays.asList(x1 + x2); List<Integer> result3 = func3.apply(2, 3); System.out.println(result3); } }
Output
5
16.0
[5]
2. BiFunction<T, U, R> + Function<T, R>
2.1 This BiFunction
takes two Integer
and returns a Double
, and uses andThen()
to chain it with a Function
to convert the Double
into a String
.
Java8BiFunction2a.java
package com.favtuts.java8; import java.util.function.BiFunction; import java.util.function.Function; public class Java8BiFunction2a { public static void main(String[] args) { // Math.pow(a1, a2) returns Double BiFunction<Integer, Integer, Double> func1 = (a1, a2) -> Math.pow(a1, a2); // takes Double, returns String Function<Double, String> func2 = (input) -> "Result : " + String.valueOf(input); String result = func1.andThen(func2).apply(2, 4); System.out.println(result); } }
Output
Result : 16.0
2.2 This example converts the above program into a method that accepts BiFunction
and Function
as arguments and chains it together.
Java8BiFunction2b.java
package com.favtuts.java8; import java.util.function.BiFunction; import java.util.function.Function; public class Java8BiFunction2b { public static void main(String[] args) { String result = powToString(2, 4, (a1, a2) -> Math.pow(a1, a2), (r) -> "Result : " + String.valueOf(r)); System.out.println(result); // Result : 16.0 } public static <R> R powToString(Integer a1, Integer a2, BiFunction<Integer, Integer, Double> func, Function<Double, R> func2) { return func.andThen(func2).apply(a1, a2); } }
Output
Result : 16.0
2.3 This example converts the above method into a generic method:
public static <A1, A2, R1, R2> R2 convert(A1 a1, A2 a2, BiFunction<A1, A2, R1> func, Function<R1, R2> func2) { return func.andThen(func2).apply(a1, a2); }
A lot of possibilities in this generic method, let see:
Java8BiFunction2c.java
package com.favtuts.java8; import java.util.function.BiFunction; import java.util.function.Function; public class Java8BiFunction2c { public static void main(String[] args) { // Take two Integers, pow it into a Double, convert Double into a String. String result = convert(2, 4, (a1, a2) -> Math.pow(a1, a2), (r) -> "Pow : " + String.valueOf(r)); System.out.println(result); // Pow : 16.0 // Take two Integers, multiply into an Integer, convert Integer into a String. String result2 = convert(2, 4, (a1, a2) -> a1 * a1, (r) -> "Multiply : " + String.valueOf(r)); System.out.println(result2); // Multiply : 4 // Take two Strings, join both, join "cde" String result3 = convert("a", "b", (a1, a2) -> a1 + a2, (r) -> r + "cde"); // abcde System.out.println(result3); // Take two Strings, join both, convert it into an Integer Integer result4 = convert("100", "200", (a1, a2) -> a1 + a2, (r) -> Integer.valueOf(r)); System.out.println(result4); // 100200 } public static <A1, A2, R1, R2> R2 convert(A1 a1, A2 a2, BiFunction<A1, A2, R1> func, Function<R1, R2> func2) { return func.andThen(func2).apply(a1, a2); } }
Output
Pow : 16.0
Multiply : 4
abcde
100200
3. Factory
3.1 This example uses BiFunction
to create an object, acts as a factory pattern.
Java8BiFunction3.java
package com.favtuts.java8; import java.util.function.BiFunction; public class Java8BiFunction3 { public static void main(String[] args) { GPS obj = factory("40.741895", "-73.989308", GPS::new); System.out.println(obj); } public static <R extends GPS> R factory(String Latitude, String Longitude, BiFunction<String, String, R> func) { return func.apply(Latitude, Longitude); } } class GPS { String Latitude; String Longitude; public GPS(String latitude, String longitude) { Latitude = latitude; Longitude = longitude; } public String getLatitude() { return Latitude; } public void setLatitude(String latitude) { Latitude = latitude; } public String getLongitude() { return Longitude; } public void setLongitude(String longitude) { Longitude = longitude; } @Override public String toString() { return "GPS{" + "Latitude='" + Latitude + '\'' + ", Longitude='" + Longitude + '\'' + '}'; } }
Output
GPS{Latitude='40.741895', Longitude='-73.989308'}
The GPS::new
calls the following constructor, which accepts two arguments and return an object (GPS), so it matches with the BiFunction
signature.
public GPS(String latitude, String longitude) {
Latitude = latitude;
Longitude = longitude;
}
4. More
4.1 Filtering a List
by some conditions.
Java8BiFunction4.java
package com.favtuts.java; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; public class Java8BiFunction4 { public static void main(String[] args) { Java8BiFunction4 obj = new Java8BiFunction4(); List<String> list = Arrays.asList("node", "c++", "java", "javascript"); List<String> result = obj.filterList(list, 3, obj::filterByLength); System.out.println(result); // [node, java, javascript] List<String> result1 = obj.filterList(list, 3, (l1, size) -> { if (l1.length() > size) { return l1; } else { return null; } }); System.out.println(result1); // [node, java, javascript] List<String> result2 = obj.filterList(list, "c", (l1, condition) -> { if (l1.startsWith(condition)) { return l1; } else { return null; } }); System.out.println(result2); // [c++] List<Integer> number = Arrays.asList(1, 2, 3, 4, 5); List<Integer> result3 = obj.filterList(number, 2, (l1, condition) -> { if (l1 % condition == 0) { return l1; } else { return null; } }); System.out.println(result3); // [2, 4] } public String filterByLength(String str, Integer size) { if (str.length() > size) { return str; } else { return null; } } public <T, U, R> List<R> filterList(List<T> list1, U condition, BiFunction<T, U, R> func) { List<R> result = new ArrayList<>(); for (T t : list1) { R apply = func.apply(t, condition); if (apply != null) { result.add(apply); } } return result; } }
Output
[node, java, javascript]
[node, java, javascript]
[c++]
[2, 4]