codestory

Die Anleitung zu Java BiFunction

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

1. BiFunction

In Java 8 ist BiFunction eine functional interface, die einen Operator darstellt, der zwei Eingabewerte akzeptiert und einen Wert zurückgibt.
Die Quellecode der 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));
    }
}
Mehr sehen: Function ist eine functional interrface ähnlich wie BiFunction, aber sie akzeptiert einen Eingabeparameter und einen Wert zurückgibt.
Zum Beispiel: Erstellt eine BiFunction, die 2 Eingabeparameter von Typen String und ein Typ von String zurückgibt.
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
Unter ist das die Liste der Methode in dem BiFunction benutzenden Paket java.util.
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)
Z.B: Ein Objekt Map enthält die Mappings zwischen dem Ländernamen und den Mietkosten einer Wohnung in einem Monat. Wir aktualisieren die Erhöhung um 10% mit der Ausnahme von Vietnam.
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)

Die Methode andThen(after) gibt eine kombinierte BiFunction zurück. Zunächst wird BiFunction.apply aufgerufen, um (T,U) in (R) umzuwandeln. Dann wird after.apply aufgerufen um (R) in (V) umzuwandeln. Wenn in einem der beiden oben genannten Schritte ein Fehler auftritt, wird der Fehler an den Anrufer übergeben. Wenn bei der aktuellen BiFunction ein Fehler auftritt, wird after ignoriert.
Der Quellcode der Methode andThen(after) kann etwas verwirrend sein:
@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));
    }
}
Und wir können den obigen Quellcode einfacher interpretieren:
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;
    }
}
Zum Beispiel:
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

Wenn eine Methode zwei Paramter akzeptiert und einen Wert zurückgibt, kann ihre Referenz als BiFunction betrachtet werden.
Z.B: Die statische Methode Math.max(int,int) akzeptiert 2 Paramter und gibt einen Integer zurück. Die Referenz lautet so: Math::max kann als BiFunction betrachtet werden.
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
Zum Beispiel: 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

Wie wir alle wissen, ist eine Konstruktor eine spezielle Methode, die ein Objekt zurückgibt. Wenn ein Konstruktor also zwei Paramter hat, wird seine Referenz als BiFunction betrachtet.
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 Grundlagen

Show More