Java : Lambda


Lambda


この文書は2021年12月21日に記録されています.
JavaのEssentialsおよびAPIドキュメントおよびその他の参照を参照してください.
関数プログラミングとは何か分からない場合は、googlingまたはPP vs OOP vs FPを参照してください.
インタフェースギネス世界記録なども理解する必要があります.
また、一等公民の関数としての内容を読んでから戻ることをお勧めします.
ランダを使うときの注意点を読むことをお勧めします.
Stream for loopforeach()に変更すべきでない3つの理由

構成


次の内容が含まれます.

  • 緒論
    1.0. Functionとは?
    1.1. 機能インタフェースとは?

  • Lamda Expression

  • Functional Interface
    3.1. Function/BiFunction/TriFunction(custom)
    3.2. Supplier
    3.3. Consumer/BiConsumer
    3.4. Predicate
    3.5. UnaryOperator

  • Practice
  • 緒論


    緒論は以下の内容から構成されている.
  • 機能とは?
  • 機能インタフェースとは?
  • メソッドリファレンスとは?
  • 簡単なコード例を実装するために、APIドキュメントを簡単に読み、参照します.
    次に、実践を通じて複雑な問題を解決しましょう.

    Functionとは?


    関数とは?
    任意の機能の一部を実現します.
    関数のコンポーネントは次のとおりです.
  • 関数名
  • 戻り値タイプ
  • パラメータタイプ
  • 関数フィールド(関数内容)
  • 機能インタフェースとは?


    デフォルトではFunctional Interface
    abstractメソッドが1つしかないインタフェースを表します.
    Lamdaと同様に、コードが簡潔であるという利点があります.

    メソッドリファレンスとは?


    メソッドの参照は次のとおりです.
    既存宣言のメソッドを指定する機能です.
    FI+Lamdaより省略が多い.
    メソッドリファレンスを使用するには、使用するメソッドのパラメータと戻りタイプを熟知する必要があります.

    Lamda Expression


    Lamda Expressionについて簡単かつ簡単に説明します.
    構造は次のとおりです.
    (Integer x)->{
       System.out.print(x);
    }
    (Integer x)->{
       return x+3;
    }
    方法と全く同じですが、形が違います.
    以下に、さらに理解すべき点を示します.
  • タイプ|できれば省略できます.
  • タイプ+括弧|パラメータが1つしかない場合は省略できます.
  • プロシージャを含む括弧|プロシージャに1行のコードしかない場合は省略できます.
  • x->System.out.print(x);
    x->x+3;

    Functional Interface


    機能インタフェースが非常に多い.
    しかし,いくつかの重要なインタフェース,あるいはそれらがルートであることにも気づいた.
    機能インタフェースには、次のものがあります.
  • Function/BiFunction/TriFunction(custom)
  • Supplier
  • Consumer/BiConsumer
  • Predicate
  • UnaryOperator
  • また、4つの演算や配列に関連付けられた出力文などの簡単な例も提供します.
    この場合、用語が長すぎるため、FI+Lamdaと表記される.

    Function


    パラメータTと戻り値R
    @FunctionalInterface
    public interface Function <T, R> {
       R apply(T t);
    }

    FI+Lamda,で第1|tを入力


    作ってみよう!
    Function <Integer, Integer> process1=(Integer number)->{
       return number+10;
    };
    Function <Integer, Integer> process2=(Integer number)->{
       return number*5;
    };
    Function <Integer, Integer> process3=(Integer number)->{
       return number/3;
    }
    省略しましょう.
    Function <Integer, Integer> process1=number->number+10;
    Function <Integer, Integer> process2=number->number*5;
    Function <Integer, Integer> process3=number->number/3;
    使ってみよう!
    System.out.print(process1.apply(50)); // 60
    System.out.print(process2.apply(50)); // 250
    System.out.print(process3.apply(50)); // 16

    BiFunction


    パラメータT、Uおよび戻り値R
    @FunctionalInterface
    public interface BiFunctioanl<T, U, R> {
       R apply(T t, U u);
    }
    制作后は省略してみます!
    BiFunction<Integer, Integer, Integer> process1=(number1, numeber2)=> number1+number2;
       
    BiFunction<Integer, Integer, Integer> process2=(number1, numeber2)=> number1-number2;
       
    BiFunction<Integer, Integer, Integer> process3=(number1, numeber2)=> number1*number2;
       
    BiFunction<Integer, Integer, Integer> process4=(number1, numeber2)=>
       (number2==0) number1 : number1/number2;
    使ってみよう!
    System.out.print(process1.apply(10,10); // 20
    System.out.print(process2.apply(10,10); // 0
    System.out.print(process3.apply(10,10); // 100
    System.out.print(process4.apply(10,0); // 10

    TriFunction (custom)


    パラメータT、U、Vおよび戻り値R
    @FunctionalInterface
    public interface TriFunction<T, U, V, R> {
    	R apply(T t, V v, R r);
    }
    制作后は省略してみます!
    TriFunction<Integer, Integer, Integer, Integer> process=(x,y,z)->x+y+z;
    使ってみよう!
    System.out.println(process.apply(100,10,1));

    Supplier


    戻り値T
    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
    制作后は省略してみます!
    Supplier<Integer> process=()->10;
    Supplier<String> process=()->"하이";
    使ってみよう!
    System.out.print(process.get());

    Consumer


    パラメータT
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
        
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }
    制作后は省略してみます!
    Consumer<Integer> process=number->System.out.print(number);
    使ってみよう!
    process.accept(10); // 10
    process.accept(30); // 30
    一体どうして.
    2021年12月21日現在、なぜ使われているのか分かりませんが、
    使える状況が見つかれば、次しかないはずです.
    publci class Main {
       public static void main(String[] args) {
          List<Integer datas=new ArrayList<>(Arrays.asList(10,20,30,40,50));
          Consumer<Integer> process=data->System.out.print(data);
       }
       
       public static void process(List<Integer> datas, Consumer<Integer> consumer) {
          for(Integer data : datas) {
             consumer.accept(data);
          }
       }
    }

    BiConsumer


    パラメータT,U
    @FunctionalInterface
    public interface BiConsumer<T, U> {
        void accept(T t, U u);
    
        default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
            Objects.requireNonNull(after);
    
            return (l, r) -> {
                accept(l, r);
                after.accept(l, r);
            };
        }
    }
    制作后は省略してみます!
    BiConsumer<Integer, String> process=(name, age)->
       System.out.printf("%s 이의 나이는 %d 입니다.%n",name,age);
    やってみる
    process.accept("unchaptered", 30);
    一体どうして.
    public class Main {
       public static void main(String[] args){
          List<String> datas=new ArrayList<>(Arrays.asList("김팔순","김덕해","홍영수"));
          BiConsumer<Integer, String> process=(index,name)->
             System.out.printf("%d 번 사용자의 이름은 %s 입니다.%n",index,name);
       }
       public static void process(List<String> datas, BiConsumer<Integer, String> process) {
          for(int i=0; i<datas.size(); i++){
             process.accept(i, list.get(i));
          }
       }
    }

    Predicate


    パラメータTと戻り値boolean
    public interface Predicate<T> {
        boolean test(T t);
    
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }
    
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
        static <T> Predicate<T> isEqual(Object targetRef) {
            return (null == targetRef)
                    ? Objects::isNull
                    : object -> targetRef.equals(object);
        }
    }
    一体どうして.
    public class Main {
    	public static void main(String[] args) {
    		Predicate<Integer> isPositive=x->x>0;
    		List<Integer> list=new ArrayList<>(Arrays.asList(10, 3, -5, 4, -2 , 0));
    		System.out.println("기본 | "+list);
    		System.out.println();
    		System.out.println(filter(list,isPositive)); // 10, 4
    		System.out.println(filter(list,isPositive.negate())); // -5, -2, 0
    		System.out.println(filter(list,isPositive.or(x->x==0))); // 10, 4, 0
    		System.out.println(filter(list,isPositive.and(x->x%2==0))); // 10, 4
    		
    		System.out.println(filter(list,isPositive.and(x->x%2==0 && x%3!=0))); // 10, 4
    		System.out.println(filter(list,isPositive.and(x->x%2==0).and(x->x%3!=0))); //10,4
    	}
    	
    	public static <T> List<T> filter(List<T> list, Predicate<T> condition) {
    		ArrayList<T> output=new ArrayList<>();
    		for(T element : list) {
    			if(condition.test(element)) {
    				output.add(element);
    			}
    		}
    		output.trimToSize();
    		return output; // 오토 업캐스팅 이루어짐
    	}
    }

    UnaryOperator


    このインタフェースはFunctionの概念を継承し、パラメータと戻り値が同じ場合、1つのタイプのパラメータのみが使用されます.
    @FunctionalInterface
    public interface UnaryOperator<T> extends Function<T, T> {
        static <T> UnaryOperator<T> identity() {
            return t -> t;
        }
    }

    Comparator

    @FunctionalInterface
    public interface Comparator<T> {
       int compare(T o1, T o2);
    }
    付録|Comparatorは比較用のインタフェースです.
    オブジェクトの比較に使用したり、単純な値の比較に使用したりできます.
  • 負水面o 1"<"o
  • 負水面o 1"="o
  • 両面o 1">"o
  • Userクラス
    public class User {
       private int id;
       private String name;
       
       public User(int id, String name) {
          this.id = id;
          this.name = name;
       }
    
       public int getId() { /* 생략 */ } }
       public String getName() { /* 생략 */ }
    
       @Override public int hashCode() { /* 생략*/ } }
       @Override public boolean equals(Object obj) { /* 생략 */ }
    
       @Override public String toString() {
          return "User [id=" + id + ", name=" + name + "]";
       }
    }
    使用状況と結果の表示
    public class UserTest {
       static void main(String[] args) {
          List<User> userList=new ArrayList<>(10);
    		
          userList.add(new User(3,"ceil"));
          userList.add(new User(1,"bellian"));
          userList.add(new User(5,"angelica"));
          System.out.println(userList+"\n");
    		
          Comparator<User> idComparator=(u1, u2)->u1.getId() - u2.getId();
          Collections.sort(userList,idComparator);
          System.out.println(userList+"\n");
    		
          Comparator<User> nameComparator=(u1, u2)->u1.getName().compareTo(u2.getName());
          Collections.sort(userList,nameComparator);
          System.out.println(userList+"\n");
       }
    }

    Method Reference


    ラムダが匿名類より優れているところでは、簡潔さが最大の特徴です.
    しかしjavaには、ramdaよりも関数オブジェクトを簡潔にする方法があります.それは方法参照です.(::演算子を使用)
    Effective Java 6 | Lamda, Stream
    次のような機能があります.
  • ClassName::staticMethodName
  • objectName::instanceMethodName
  • ClassName::instanceMethodName
  • ClassName::new
  • ClassName::staticMethodName

    Function<String, Integer> strToint=Integer::parseInt;
    int number=strToint.apply("403");
    System.out.print(number); // 403

    objectName::instanceMethodName

    String textA="hello";                     
    String textB="world";                     
    Predicate<String> equalsStrToStr=textA::equals
    boolean bools=equalsStrToStr.test("hello"); // true
    boolean bools2=equalsStrToStr.test(textA); // true
    boolean bools3=equalsStrToStr.test(textB); // false

    拡張


    FI+LamdaとLazy Evaluationの使用


    Supplierを使用してパフォーマンス+Lazy Evaluationを向上させる理由
    上の使用例を見ているだけでは理由が分からないと思います.
    しかし、Supplierが演算を担当すると、物語は異なります.
    パラメータに一般関数を渡すと、すぐに実行されます.
    ただし、Supplierはget()で実行時間を決定することができる.
    これらを利用できるのがLazy Evaluationの概念です.

    Lazy Evaluation


    [Avascript]遅延評価によるパフォーマンスの向上
    @Functional Interfaceを使用して、特定の機能の実行時間を決定できます.
    この部分を理解していない人がいたら、下をチェックしてください.
    hello() // 기존의 메서드 방식
    hello.get() // Functional Interface 에서 추구하는 방식
    一般的な方法では,実行時間を名前()の形式で決定することは困難である.
    ただし、@Functional Interfaceでは、名前.実行関数()の形式では、パラメータ化と呼び出しの実行を分離する大きな利点があります.
    これは厳密な評価とLazy評価を実現できる.
    上記のリンクから入る言語はJavaScriptに基づいています.
    Javaベースの説明を探しましたが、完全な効果を説明する文章を見つけるのは難しいです.上の文章はもっと簡潔で正確に追加されています.
    const arr = [0, 1, 2, 3, 4, 5]
    const result = arr.map(num => num + 10).filter(num => num % 2).slice(0, 2)
    console.log(result) // [11, 13]
    // 지연평가를 하기 위해서는 지연평가 용 함수(Java 의 Functional Interface) 를 만들어야 한다.
    const arr = [0, 1, 2, 3, 4, 5]
    const result = _.take(2, L.filter(num => num % 2, L.map(num => num + 10, arr)));
    console.log(result) // [11, 13]
    この内容の詳細については、下記の記事を参考にしてください.
    [JS]ES 6による関数式プログラミング-12 take