当サイトは、アフィリエイト広告を利用しています
javaで関数側インターフェースを使ってみる。
javascriptでいうところの高階関数のように変数の中に関数を入れることができる。
javaで関数型インターフェースというインターフェースがあり、その型の変数に
関数を入れて扱うことができる。
関数型インターフェースにはいくつか種類があり、インターフェースごとに設定できる
関数の形(引数の数や戻り値)などが決まっている。
独自の関数を使いたい場合は関数型インターフェースを継承したクラスを作成する必要がある。
関数型インターフェースのうち、Functionインターフェース型は 引数と戻り値がある関数を入れることができる。
Function <Integer,String> make1 = a -> a + "です";
つまりmake1は引数がInteger型、戻り値がString型の関数を格納することができる。
実行する場合は下記のようになる
String b = make1.apply(2);
applyメソッドでmake1内の関数を実行している。
関数型インターフェースを使ったプログラムを書いてみる
ラムダ式も使用して!
import java.util.*;import java.util.function.*;import java.util.stream.Collectors;public class Main {public static void main(String[] args) throws Exception {//Personクラスclass Person {private String name;public Person(String name){this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}}//名前のリストを作成List<String>nameList = Arrays.asList("aa","bb","cc");//Functionインターフェースを使って//名前リスト分のPersonオブジェクトを作成し、Listに格納する関数を変数:genPersonに設定する// ラムダ式のmapを使うFunction<List<String>,List<Person>> genPerson = (list)->list.stream().map((name)-> new Person(name)).collect(Collectors.toList());//変数に格納された関数をapplyメソッドで実行するList<Person>resultList2 = genPerson.apply(nameList);//BiFunctionインターフェースを使って//PresonListの中に指定した名前が何個あるか調べる関数を変数:searchNameCountに設定する//BiFunction<第一引数の型,第二引数の型,戻り値の型>BiFunction<String,List<Person>,Integer> searchNameCount = (searchName,list2) -> {//ラムダ式のfilterを使うreturn list2.stream().filter( (per)->searchName.equals(per.getName())).collect(Collectors.toList()).size();};//変数:searchNameCount内の変数をapplyメソッドで実行する。System.out.println(searchNameCount.apply("addda",resultList2));//関数の引数に関数を設定することもできる//第三引数に戻り値がList<Person>である関数の入ったgenPersonを設定している。System.out.println(searchNameCount.apply("bb",genPerson.apply(nameList)));}}
蛇足だが上記のサンプルのラムダ部分の別の書き方でかくこともできる
※上記は省略したラムダ式で書いている。
import java.util.*;import java.util.function.*;import java.util.stream.Collectors;public class Main {public static void main(String[] args) throws Exception {class Person {private String name;public Person(String name){this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}}List<String>nameList = Arrays.asList("aa","bb","cc");// 省略なしFunction<List<String>,List<Person>> genPerson = (list)->{List<Person>resultList = list.stream().map((name)->{return new Person(name);}).collect(Collectors.toList());return resultList;};List<Person>resultList2 = genPerson.apply(nameList);BiFunction<String,List<Person>,Integer> searchNameCount = (searchName,list2) -> {//省略なしList<Person>resList = list2.stream().filter( (per)->{if (searchName.equals(per.getName())){return true;}else {return false;}}).collect(Collectors.toList());return resList.size();};//普通に呼ぶSystem.out.println(searchNameCount.apply("addda",resultList2));//関数の中で関数を呼ぶこともできるSystem.out.println(searchNameCount.apply("bb",genPerson.apply(nameList)));}}
またmapの部分をforEachで書くこともできる
import java.util.*;import java.util.function.*;import java.util.stream.Collectors;public class Main {public static void main(String[] args) throws Exception {class Person {private String name;public Person(String name){this.name = name;}public String getName() {return this.name;}public void setName(String name) {this.name = name;}}List<String>nameList = Arrays.asList("aa","bb","cc");// forEachを使う場合Function<List<String>,List<Person>> genPerson = (list)->{List<Person>resultList = new ArrayList<>();list.stream().forEach((name)->{// Person person = null;Person person = new Person(name);resultList.add(person);});return resultList;};List<Person>resultList2 = genPerson.apply(nameList);// Your code here!BiFunction<String,List<Person>,Integer> searchNameCount = (searchName,list2) -> {//省略なしList<Person>resList = list2.stream().filter( (per)->{if (searchName.equals(per.getName())){return true;}else {return false;}}).collect(Collectors.toList());return resList.size();};//普通に呼ぶSystem.out.println(searchNameCount.apply("addda",resultList2));//関数の中で関数を呼ぶこともできるSystem.out.println(searchNameCount.apply("bb",genPerson.apply(nameList)));}}
Java 関数型インターフェースのサンプル(Function)
既に書いたが関数型インターフェース内でラムダ式を書く場合に
書き方にいくかパターンがあるのでまとめておく。
Predicateインターフェースを使ってListの中から
奇数だけを探す関数を使ってサンプルを書く
基本のパターン。
変数に関数をいれて、testメソッドで実行している
import java.util.*;import java.util.function.*;import java.util.function.*;import java.util.stream.Collectors;public class Main {public static void main(String[] args) throws Exception {// 奇数を判定するPredicatevar numbers = List.of(18, 4, 22, 7, 31, 1, 12, 25, 36, 3);// 奇数を判定するPredicate//Predicateは一つの引数をとり、boolean型の戻り値を返すインターフェース//Integerは引数の型Predicate<Integer> isOdd = x -> x % 2 != 0;//Predicateではtestメソッドで変数の中の関数を実行するnumbers.stream().filter(x -> isOdd.test(x)).forEach(x->System.out.print(x));}}
通常、Functionインターフェース型であればapplyメソッド
Predicateインターフェース型であればtestメソッドで変数内の
関数を実行するがラムダ式の中で使う時はそれを省略できる場合がある。
import java.util.*;import java.util.function.*;import java.util.function.*;import java.util.stream.Collectors;public class Main {public static void main(String[] args) throws Exception {// 奇数を判定するPredicatevar numbers = List.of(18, 4, 22, 7, 31, 1, 12, 25, 36, 3);// 奇数を判定するPredicate//Predicateは一つの引数をとり、boolean型の戻り値を返すインターフェース//Integerは引数の型Predicate<Integer> isOdd = x -> x % 2 != 0;//ラムダの中で直接、isOddを呼ぶ//testメソッドなしでも実行可能。numbers.stream().filter(isOdd).forEach(x->System.out.print(x));}
変数に格納されている関数がラムダ式内で展開しても
問題なく実行できる場合はapplyメソッドやtestメソッドなしでも
実行できる。
// 奇数を判定するPredicatevar numbers = List.of(18, 4, 22, 7, 31, 1, 12, 25, 36, 3);// 奇数を判定するPredicatePredicate<Integer> isOdd = x -> x % 2 != 0;//isOddに格納されてる関数をそのままfilter内で展開しても実行できるnumbers.stream().filter(x -> x % 2 != 0).forEach(x->System.out.print(x));//上記のような場合は省略して書くことができるnumbers.stream().filter(isOdd).forEach(x->System.out.print(x));