betacode

Руководство Java BiFunction

  1. BiFunction
  2. andThen(Function after)
  3. BiFunction + Method reference
  4. BiFunction + Constructor reference

1. BiFunction

В Java 8, BiFunction ялвяетсяfunctional interface, представляющим оператор, который принимает два входных значения и возвращает одно значение.
Исходный код интерфейса BiFunction:
BiFunction
@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
 
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}
См.Также: Function является functional interrface, подобным BiFunction, но он принимает входной параметр и возвращает значение.
Например: Создание BiFunction, которая принимает 2 входных параметра типа String и возвращает String.
BiFunctionEx1.java
package org.o7planning.bifunction.ex;

import java.util.function.BiFunction;

public class BiFunctionEx1 {
    
    public static void main(String[] args) {
        
        // Create a BiFunction object directly.
        // Accepts 2 input parameters of type String and return a String.
        BiFunction<String, String, String> namer //
                = (firstName, lastName) -> firstName + " " + lastName;

        String fullName = namer.apply("James", "Smith");

        System.out.println(fullName);
    }
}
Output:
James Smith
Ниже приведен список методов в package java.util, использующих BiFunction:
V
HashMap.compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
Hashtable.compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
default V
Map.compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
TreeMap.compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
HashMap.computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
Hashtable.computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
default V
Map.computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
TreeMap.computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
V
HashMap.merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
V
Hashtable.merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
default V
Map.merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
V
TreeMap.merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)
default void
Map.replaceAll(BiFunction<? super K,? super V,? extends V> function)
Например: Объект Map содержит сопоставления между названием страны и стоимостью аренды квартиры в месяц. Мы повысим цены на 10%, за исключением Вьетнама.
BiFunctionEx2.java
package org.o7planning.bifunction.ex;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;

public class BiFunctionEx2 {

    public static void main(String[] args) {
        // Data in 2021.
        // String country --> Float price to rent an apartment per month ($).
        Map<String, Float> pricingMap = new HashMap<String, Float>();

        pricingMap.put("Singapore", 2147f);
        pricingMap.put("Sweden", 890f);
        pricingMap.put("Japan", 770f);
        pricingMap.put("Mexico", 345f);
        pricingMap.put("Vietnam", 305f);
        pricingMap.put("India", 156f);
        
        // Pricing Map
        System.out.println(pricingMap);
        System.out.println();

        // (String,Float) --> Float.
        BiFunction<String, Float, Float> biFunction = (country, price) -> {
            if (country.equals("Vietnam")) {
                return price;
            }
            return price * 1.1f;
        };
        
        pricingMap.replaceAll(biFunction);
        
        // After replacement.
        System.out.println("After replacement:\n");
        System.out.println(pricingMap);
    }
}
Output:
{Sweden=890.0, Vietnam=305.0, Singapore=2147.0, Japan=770.0, Mexico=345.0, India=156.0}

After replacement:

{Sweden=979.0, Vietnam=305.0, Singapore=2361.7, Japan=847.0, Mexico=379.5, India=171.6}

2. andThen(Function after)

Метод andThen(after) возвращает комбинированную BiFunction. В начале, BiFunction.apply вызывается для преобразования (T,U) в (R), затем after.apply вызывается для преобразования (R) в (V). Если на одном из вышеперечисленных 2 шагов возникает ошибка, она передается вызывающему абоненту (caller). Если в текущей BiFunction возникает ошибка, то after игнорируется.
Исходный код метода andThen(after) может быть немного запутанным:
@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);

    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}
И мы можем интерпретировать приведенный выше исходный код более простым способом:
BiFunction (Simpler)
@FunctionalInterface
public interface BiFunction<T, U, R> {
    // (T,U) -> R
    R apply(T t, U u);

    // (T,U) -> V
    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        
        BiFunction<T, U, V> ret = (T t, U u) -> {
            // (T,U) -> R
            R r = this.apply(t, u);    
            
            // R -> V
            V v = after.apply(r);
            return v;
        };
        
        return ret;
    }
}
Например:
BiFunction_andThen_ex1.java
package org.o7planning.bifunction.ex;

import java.util.function.Function;

public class BiFunction_andThen_ex1 {

    public static void main(String[] args) {
        // BiFunction: (char,int) --> (String)
        // Example: ('0', 3)  --> "000"
        BiFunction<Character, Integer, String> bif = (ch, n) -> {
            String s="";
            for(int i=0;i< n;i++) {
                s+=ch;
            }
            return s;
        };
        // Function: (String) --> (String)
        // Example: "abc" --> "ABC".
        Function<String,String> after = s -> s.toUpperCase();
        
        // Test:
        String result = bif.andThen(after).apply('a', 3);
        System.out.println("Result: " + result);
    }
}
Output:
Result: AAA

3. BiFunction + Method reference

Если метод принимает два параметра и возвращает значение, то его ссылку можно рассматривать как BiFunction.
Например: Статический метод Math.max(int,int) принимает 2 параметра и возвращает целое число Integer. Таким образом, его ссылку - Math::max можно считать BiFunction.
BiFunction_mRef_ex1.java
package org.o7planning.bifunction.ex;

public class BiFunction_mRef_ex1 {

    public static void main(String[] args) {
        // Create a BiFunction from method reference.
        // (Integer,Integer) --> (Integer)
        BiFunction<Integer, Integer, Integer> biFunc = Math::max;

        int max = biFunc.apply(10,  20); // 20
        
        System.out.println("Max: " + max); // 20
    }
}
Output:
Max: 20
Например: BiFunction + non-static method reference:
BiFunction_mRef_ex2.java
package org.o7planning.bifunction.ex;

public class BiFunction_mRef_ex2 {

    public static void main(String[] args) {
        CardTemplate template = new CardTemplate("Designed by Tom");

        // Create a BiFunction from method reference.
        // (String,String) --> (String)
        BiFunction<String, String, String> biFunc = template::getContent;

        String cardContent = biFunc.apply("Eli", "Smith");

        System.out.println(cardContent);
    }
}

class CardTemplate {
    private String someInfo;

    public CardTemplate(String someInfo) {
        this.someInfo = someInfo;
    }

    public String getContent(String firstName, String lastName) {
        return "----- ~~~~~ -----\n" //
                + "First name: " + firstName + "\n" //
                + "Last name: " + lastName + "\n" //
                + this.someInfo;
    }
}
Output:
----- ~~~~~ -----
First name: Eli
Last name: Smith
Designed by Tom

4. BiFunction + Constructor reference

Как мы все знаем, constructor - это специальный метод, который возвращает объект. Таким образом, если constructor имеет 2 параметра, его ссылка будет рассматриваться как BiFunction.
BiFunction_cRef_ex1.java
package org.o7planning.bifunction.ex;

public class BiFunction_cRef_ex1 {

    public static void main(String[] args) {
        // Create a BiFunction from constructor reference.
        // (String,Integer) --> (Staff)
        BiFunction<String, Integer, Staff> biFunc = Staff::new;

        Staff tom = biFunc.apply("Tom", 1000);
        Staff jerry = biFunc.apply("Jerry", 2000);
        
        tom.showInfo();
        jerry.showInfo();
    }
    
    public static class Staff {
        private String fullName;
        private int salary;

        public Staff(String fullName,int salary)  {
            this.fullName= fullName;
            this.salary = salary;
        }
        public String getFullName() {
            return fullName;
        }
        public int getSalary() {
            return salary;
        }
        public void showInfo()  {
            System.out.println("Full Name: " + this.fullName +", Salary: " + this.salary);
        }
    }
}
Output:
Full Name: Tom, Salary: 1000
Full Name: Jerry, Salary: 2000

Java Basic

Show More