【Javaベース】:JavaのLambda式適用

91585 ワード

1.はじめに
最近Flinkのソースコードを研究して、中に多くのLambda式があることを発見して、いくつかの用法はまだそんなにはっきりしていないで、すべて専門的に資料を調べて、JavaのLambda式の応用に対していくつか総括を行います.Lambda式はJava SE 8の中で1つの重要な新しい特性です.Lambda式では、機能インタフェースの代わりに式を使用できます.Lambda式は、メソッドと同様に、通常のパラメータリストと、これらのパラメータを使用するボディ(body、式またはコードブロック)を提供します.Lambda式は集合ライブラリも強化した.Java SE 8には、集合データを一括操作するパッケージとしてjava.util.functionパッケージとjava.util.streamパッケージの2つが追加されています.ストリーム(stream)は反復器(iterator)のようなものですが、多くの追加機能が付加されています.総じてlambda式とstreamはJava言語に汎用(Generics)と注釈(annotation)を追加して以来最大の変化である.本稿では,lambda式とstreamの強さを認識する単純から複雑な例を参照する.環境準備Java 8がまだインストールされていない場合は、lambdaとstreamを使用する前にインストールする必要があります(翻訳者は仮想マシンにインストールし、テストして使用することをお勧めします).NetBeansやIntelliJ IDEAのようなツールやIDEは、lambda式、重複可能な注釈、コンパクトなプロファイル、その他の特性を含むJava 8特性をサポートします.Java SE 8とNetBeans IDE 8のダウンロードリンクは、Java Platform(JDK 8):OracleからJava 8をダウンロードするか、NetBeans IDEとともにNetBeans IDEをダウンロードできます8:NetBeans公式サイトからNetBeans IDE Lambda式の構文基本構文をダウンロードします:(parameters)->expressionまたは(parameters)->statements;}
2.使用例
Java lambda式の簡単な例を次に示します.
// 1.      ,     5  
() -> 5  
  
// 2.       (    ),   2     
x -> 2 * x  
  
// 3.   2   (  ),          
(x, y) -> x – y  
  
// 4.   2 int   ,        
(int x, int y) -> x + y  
  
// 5.      string   ,       ,      (       void)  
(String s) -> System.out.print(s)

基本的なLambdaの例
今、lambda式とは何かを知っています.まず、いくつかの基本的な例から始めましょう.このセクションでは、lambda式が私たちの符号化方法にどのように影響するかを示します.プレイヤーリストがあると仮定すると、プログラマーはfor文(「forループ」)を使って巡回することができ、Java SE 8で別の形式に変換することができる.
String[] atp = {"Rafael Nadal", "Novak Djokovic",  
       "Stanislas Wawrinka",  
       "David Ferrer","Roger Federer",  
       "Andy Murray","Tomas Berdych",  
       "Juan Martin Del Potro"};  
List<String> players =  Arrays.asList(atp);  
  
//          
for (String player : players) {  
     System.out.print(player + "; ");  
}  
  
//    lambda          (functional operation)  
players.forEach((player) -> System.out.print(player + "; "));  
   
//   Java 8          (double colon operator)  
players.forEach(System.out::println);

ご覧のように、lambda式は私たちのコードを1行に縮小することができます.もう1つの例は、グラフィックユーザインタフェースプログラムでは、匿名クラスをlambda式で置き換えることができる.同様に、Runnableインタフェースを実装する際にも、次のように使用できます.
//          
btn.setOnAction(new EventHandler<ActionEvent>() {  
          @Override  
          public void handle(ActionEvent event) {  
              System.out.println("Hello World!");   
          }  
    });  
   
//      lambda expression  
btn.setOnAction(event -> System.out.println("Hello World!"));

次に、lambdasを使用してRunnableインタフェースを実装する例を示します.
// 1.1         
new Thread(new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("Hello world !");  
    }  
}).start();  
  
// 1.2   lambda expression  
new Thread(() -> System.out.println("Hello world !")).start();  
  
// 2.1         
Runnable race1 = new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("Hello world !");  
    }  
};  
  
// 2.2   lambda expression  
Runnable race2 = () -> System.out.println("Hello world !");  
   
//      run   (      !)  
race1.run();  
race2.run();

Runnableのlambda式は、ブロックフォーマットを使用して5行のコードを1行の文に変換します.次に、次のセクションではlambdasを使用してコレクションをソートします.
Lambdasを使用してコレクションをソートする
Javaでは、Comparatorクラスがセットをソートするために使用されます.次の例では、選手のname、surname、nameの長さ、最後のアルファベットに基づいています.前の例と同様に、匿名の内部クラスを使用してソートし、lambda式を使用してコードを簡略化します.最初の例では、nameに基づいてlistをソートします.古い方法では、コードは次のようになります.
String[] players = {"Rafael Nadal", "Novak Djokovic",   
    "Stanislas Wawrinka", "David Ferrer",  
    "Roger Federer", "Andy Murray",  
    "Tomas Berdych", "Juan Martin Del Potro",  
    "Richard Gasquet", "John Isner"};  
   
// 1.1           name    players  
Arrays.sort(players, new Comparator<String>() {  
    @Override  
    public int compare(String s1, String s2) {  
        return (s1.compareTo(s2));  
    }  
});

Lambdasを使用すると、次のコードで同じ機能を実現できます.
// 1.2    lambda expression    players  
Comparator<String> sortByName = (String s1, String s2) -> (s1.compareTo(s2));  
Arrays.sort(players, sortByName);  
  
// 1.3          :  
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2))); 

その他のソートは以下の通りです.上記の例と同様に、コードは匿名の内部クラスといくつかのlambda式によってComparatorを実現します.
// 1.1           surname    players  
Arrays.sort(players, new Comparator<String>() {  
    @Override  
    public int compare(String s1, String s2) {  
        return (s1.substring(s1.indexOf(" ")).compareTo(s2.substring(s2.indexOf(" "))));  
    }  
});  
  
// 1.2    lambda expression   ,   surname  
Comparator<String> sortBySurname = (String s1, String s2) ->   
    ( s1.substring(s1.indexOf(" ")).compareTo( s2.substring(s2.indexOf(" ")) ) );  
Arrays.sort(players, sortBySurname);  
  
// 1.3     ,           ,    ...  
Arrays.sort(players, (String s1, String s2) ->   
      ( s1.substring(s1.indexOf(" ")).compareTo( s2.substring(s2.indexOf(" ")) ) )   
    );  
  
// 2.1           name lenght    players  
Arrays.sort(players, new Comparator<String>() {  
    @Override  
    public int compare(String s1, String s2) {  
        return (s1.length() - s2.length());  
    }  
});  
  
// 2.2    lambda expression   ,   name lenght  
Comparator<String> sortByNameLenght = (String s1, String s2) -> (s1.length() - s2.length());  
Arrays.sort(players, sortByNameLenght);  
  
// 2.3 or this  
Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length()));  
  
// 3.1           players,           
Arrays.sort(players, new Comparator<String>() {  
    @Override  
    public int compare(String s1, String s2) {  
        return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));  
    }  
});  
  
// 3.2    lambda expression   ,          
Comparator<String> sortByLastLetter =   
    (String s1, String s2) ->   
        (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));  
Arrays.sort(players, sortByLastLetter);  
  
// 3.3 or this  
Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));

このように、簡潔で直感的です.次のセクションでは、より多くのlambdasの能力を探求し、streamと組み合わせて使用します.
LambdasとStreamsの使用
Streamは集合のパッケージで、通常はlambdaと一緒に使用されます.lambdasを使用すると、map、filter、limit、sorted、count、min、max、sum、collectなど、多くの操作をサポートできます.同様に、Streamは怠け者の演算を使用しており、実際にすべてのデータを読み取ることはなく、getFirst()のような方法でチェーン構文を終了します.次の例では、lambdasとstreamsが何ができるかを探索します.Personクラスを作成し、listにデータを追加するためにこのクラスを使用し、さらなるストリーム操作に使用します.Personは単純なPOJOクラスにすぎません.
public class Person {  
  
private String firstName, lastName, job, gender;  
private int salary, age;  
  
public Person(String firstName, String lastName, String job,  
                String gender, int age, int salary)       {  
          this.firstName = firstName;  
          this.lastName = lastName;  
          this.gender = gender;  
          this.age = age;  
          this.job = job;  
          this.salary = salary;  
}  
// Getter and Setter   
// . . . . .  
}

次に、Personオブジェクトを格納するために2つのlistを作成します.
List<Person> javaProgrammers = new ArrayList<Person>() {  
  {  
    add(new Person("Elsdon", "Jaycob", "Java programmer", "male", 43, 2000));  
    add(new Person("Tamsen", "Brittany", "Java programmer", "female", 23, 1500));  
    add(new Person("Floyd", "Donny", "Java programmer", "male", 33, 1800));  
    add(new Person("Sindy", "Jonie", "Java programmer", "female", 32, 1600));  
    add(new Person("Vere", "Hervey", "Java programmer", "male", 22, 1200));  
    add(new Person("Maude", "Jaimie", "Java programmer", "female", 27, 1900));  
    add(new Person("Shawn", "Randall", "Java programmer", "male", 30, 2300));  
    add(new Person("Jayden", "Corrina", "Java programmer", "female", 35, 1700));  
    add(new Person("Palmer", "Dene", "Java programmer", "male", 33, 2000));  
    add(new Person("Addison", "Pam", "Java programmer", "female", 34, 1300));  
  }  
};  
  
List<Person> phpProgrammers = new ArrayList<Person>() {  
  {  
    add(new Person("Jarrod", "Pace", "PHP programmer", "male", 34, 1550));  
    add(new Person("Clarette", "Cicely", "PHP programmer", "female", 23, 1200));  
    add(new Person("Victor", "Channing", "PHP programmer", "male", 32, 1600));  
    add(new Person("Tori", "Sheryl", "PHP programmer", "female", 21, 1000));  
    add(new Person("Osborne", "Shad", "PHP programmer", "male", 32, 1100));  
    add(new Person("Rosalind", "Layla", "PHP programmer", "female", 25, 1300));  
    add(new Person("Fraser", "Hewie", "PHP programmer", "male", 36, 1100));  
    add(new Person("Quinn", "Tamara", "PHP programmer", "female", 21, 1000));  
    add(new Person("Alvin", "Lance", "PHP programmer", "male", 38, 1600));  
    add(new Person("Evonne", "Shari", "PHP programmer", "female", 40, 1800));  
  }  
};

forEachメソッドを使用して、上記のリストを反復出力します.
System.out.println("        :");  
javaProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));  
phpProgrammers.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName())); 

私たちはforEachメソッドを使用して、プログラマーの給料を5%増やします.
System.out.println("       5% :");  
Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());  
  
javaProgrammers.forEach(giveRaise);  
phpProgrammers.forEach(giveRaise);  

もう1つの有用な方法はフィルタフィルタ()で、月給が1400ドルを超えるPHPプログラマーを表示します.
System.out.println("        $1,400  PHP   :")  
phpProgrammers.stream()  
          .filter((p) -> (p.getSalary() > 1400))  
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));  

フィルタを定義し、再利用して他の操作を実行することもできます.
//    filters  
Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);  
Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400);  
Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender()));  
  
System.out.println("        24     $1,400    PHP   :");  
phpProgrammers.stream()  
          .filter(ageFilter)  
          .filter(salaryFilter)  
          .filter(genderFilter)  
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));  
  
//   filters  
System.out.println("     24     Java programmers:");  
javaProgrammers.stream()  
          .filter(ageFilter)  
          .filter(genderFilter)  
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

limitメソッドを使用すると、結果セットの数を制限できます.
 System.out.println("    3  Java programmers:");  
javaProgrammers.stream()  
          .limit(3)  
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));  
  
  
System.out.println("    3    Java programmers:");  
javaProgrammers.stream()  
          .filter(genderFilter)  
          .limit(3)  
          .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));

ソートは?streamで処理できますか?答えは肯定的だ.次の例では、Javaプログラマーを名前と給与に基づいてソートし、リストに配置してリストを表示します.
System.out.println("   name   ,    5  Java programmers:");  
List<Person> sortedJavaProgrammers = javaProgrammers  
          .stream()  
          .sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName())))  
          .limit(5)  
          .collect(toList());  
  
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));  
   
System.out.println("   salary    Java programmers:");  
sortedJavaProgrammers = javaProgrammers  
          .stream()  
          .sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) )  
          .collect( toList() );  
  
sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));

最低賃金と最高賃金だけに興味がある場合は、ソート後に最初の/最後の1つを選択するよりも速いのはminとmaxの方法です.
System.out.println("      Java programmer:");  
Person pers = javaProgrammers  
          .stream()  
          .min((p1, p2) -> (p1.getSalary() - p2.getSalary()))  
          .get()  
  
System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary())  
  
System.out.println("      Java programmer:");  
Person person = javaProgrammers  
          .stream()  
          .max((p, p2) -> (p.getSalary() - p2.getSalary()))  
          .get()  
  
System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary())

上記の例ではcollectメソッドがどのように動作しているかを示しています.mapメソッドと組み合わせて、collectメソッドを使用して、結果セットを文字列、Set、またはTreeSetに配置できます.
System.out.println("  PHP programmers   first name       :");  
String phpDevelopers = phpProgrammers  
          .stream()  
          .map(Person::getFirstName)  
          .collect(joining(" ; ")); //               (token)     
  
System.out.println("  Java programmers   first name     Set:");  
Set<String> javaDevFirstName = javaProgrammers  
          .stream()  
          .map(Person::getFirstName)  
          .collect(toSet());  
  
System.out.println("  Java programmers   first name     TreeSet:");  
TreeSet<String> javaDevLastName = javaProgrammers  
          .stream()  
          .map(Person::getLastName)  
          .collect(toCollection(TreeSet::new));  

Streamsはパラレル(parallel)でもよい.例は次のとおりです.
System.out.println("     Java programmers    money:");  
int totalSalary = javaProgrammers  
          .parallelStream()  
          .mapToInt(p -> p.getSalary())  
          .sum();  

summaryStatistics法を用いてstream中の要素の様々な要約データを得ることができる.次に、getMax、getMin、getSum、getAverageなどの方法にアクセスします.
//   count, min, max, sum, and average for numbers  
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);  
IntSummaryStatistics stats = numbers  
          .stream()  
          .mapToInt((x) -> x)  
          .summaryStatistics();  
  
System.out.println("List       : " + stats.getMax());  
System.out.println("List       : " + stats.getMin());  
System.out.println("          : " + stats.getSum());  
System.out.println("         : " + stats.getAverage());

3.まとめ
これらの操作はFlinkのチェーン操作と似ているかどうか.
リファレンス
  • https://www.cnblogs.com/franson-2016/p/5593080.html