【JavaGold】関数型インタフェースとラムダ式

# `関数型インタフェースとラムダ式`

<table>
  <caption>関数型インタフェース</caption>
  <thead>
    <tr>
      <th>パッケージ</th>
      <th>インタフェース</th>
      <th>戻り値型</th>
      <th>メソッド</th>
    </tr>
  </thead>
  <tr>
    <td>java.utill.function</td>
    <td>Supplier< T ></td>
    <td>T</td>
    <td>get()</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>Consumer< T ></td>
    <td>void</td>
    <td>accept(T)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>BiConsumer< T , U ></td>
    <td>void</td>
    <td>accept(T,U)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>Predicate< T ></td>
    <td>boolean</td>
    <td>test(T)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>BiPredicate< T , U ></td>
    <td>boolean</td>
    <td>test(T,U)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>Function< T , R ></td>
    <td>R</td>
    <td>apply(T)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>BiFunction< T , U , R ></td>
    <td>R</td>
    <td>apply(T,U)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>UnaryOperator< T ></td>
    <td>T</td>
    <td>apply(T)</td>
  </tr>
  <tr>
    <td>java.utill.function</td>
    <td>BinaryOperator< T ></td>
    <td>T</td>
    <td>apply(T,T)</td>
  </tr>
  <tr>
    <td>java.lang</td>
    <td>Runnable</td>
    <td>void</td>
    <td>run()</td>
  </tr>
  <tr>
    <td>java.util.concurrent</td>
    <td>Callable< V ></td>
    <td>V</td>
    <td>call()</td>
  </tr>
</table>

## `Function<T, R>`

### `apply(T)`
`Function<T, R>` の抽象メソッド。
`T`型の引数を受け取って、`R`型の値を返す処理を実装する。

```java:実装例
package sample;

import java.util.function.Function;

public class Sample {
    public static void main(String[] args) {
        Function<String, Integer> function = string -> Integer.parseInt(string);
        System.out.println(function.apply("12345"));
    }
}
```

```:実行結果
12345
```

### `andThen(Function<? super R,? extends V>)`
前から後ろの順序で実行される。(順次処理)

```java:実装例
package sample;

import java.util.function.Function;

public class Sample {
    public static void main(String[] args) {
        Function<Integetr, Integetr> a = x -> x + 2;
        Function<Integetr, Integetr> b = x -> x * 2;

        Function<Integetr, Integetr> c = a.andThen(b);
        System.out.println(c.apply(10));
        
        System.out.println(a.andThen(b).apply(10));

        System.out.println(b.apply(a.apply(10)));
    }
}
```

```:実行結果
24
24
24
```

### `compose(Function<? super V,? extends T>)`
後ろから前の順序で実行される。(逆順処理)

```java:実装例
package sample;

import java.util.function.Function;

public class Sample {
    public static void main(String[] args) {
        Function<Integetr, Integetr> a = x -> x + 2;
        Function<Integetr, Integetr> b = x -> x * 2;

        Function<Integetr, Integetr> c = a.compose(b);
        System.out.println(c.apply(10));
        
        System.out.println(a.compose(b).apply(10));

        System.out.println(a.apply(b.apply(10)));
    }
}
```

```:実行結果
22
22
22
```

### `identity()`
static メソッド。
`apply(T)`メソッドに渡した値をそのまま返す`Function`オブジェクトを生成する。

```java:実装例
package sample;

import java.util.function.Function;

public class Sample {
    public static void main(String[] args) {
        Function<String, String> function = Function.identity();
        System.out.println(function.apply("string message"));
    }
}
```

```:実行結果
string message
```

### `UnaryOperator<T>`
`Function`の拡張インターフェース。
`Function`の型引数が２つとも同じ型、つまり、引数と戻り値の同じ型を返す特別パターン。
１つの値を処理して同じ型の処理を戻す。

```java:実装例
package sample;

import java.util.function.UnaryOperator;

public class Sample {
    public static void main(String[] args) {
        UnaryOperator<String> unary = string -> "[" + string + "]";
        System.out.println(unary.apply("test"));
    }
}
```

```:実行結果
[test]
```

## `Consumer<T>`
### `accept(T)`

`Consumer<T>`の抽象メソッド。
`T`型の値を引数に受け取って、戻り値無しの処理を実装する。

```java:実装例
package sample;

import java.util.function.Consumer;

public class Sample {
    public static void main(String[] args) {
        Consumer<String> consumer = string -> System.out.println(string);
        consumer.accept("test");
    }
}
```

```:実行結果
test
```

### `andThen(Consumer<? super T>)`

「andThen() メソッドを実行した Consumer オブジェクト」→「引数で渡した Consumer オブジェクト」の順序で処理を実行する新しい Consumer オブジェクトが生成される。

```java:実装例
package sample;
import java.util.function.Consumer;

public class Sample {
    public static void main(String[] args) {
        Consumer<String> hoge = string -> System.out.println("hoge : " + string);
        Consumer<String> fuga = string -> System.out.println("fuga : " + string);

        Consumer<String> piyo = hoge.andThen(fuga);

        piyo.accept("piyo");
    }
}
```

```:実行結果
hoge : piyo
fuga : piyo
```

```java:実装例
import java.util.List;
import java.util.function.Consumer;

public class Sample {
    public static void main(String[] args) {
        List<String> list = List.of("A", "B", "C");
        Consumer<String> a = System.out::print;
        Consumer<String> b = a.andThen(
                                str -> 
                                System.out.println(":" + str.toLowerCase()
                             );
        list.forEach(b);
    }
}
```

```:実行結果
A:a B:b C:c
```

## `Supplier<T>`
### `get()`

`Supplier<T>`の抽象メソッド。
`T`型の値を返す処理を実装する。

```java:実装例
package sample;

import java.util.function.Supplier;

public class Sample {
    public static void main(String[] args) {
        Supplier<String> supplier = () -> "test";
        System.out.println(supplier.get());
    }
}
```

```:実行結果
test
```

## `Predicate<T>`
### `test(T)`

`Predicate<T>`の抽象メソッド。
`T`型の値を引数に受け取って、booleanの値を返す処理を実装する。

```java:実装例
package sample;

import java.util.function.Predicate;

public class Sample {
    public static void main(String[] args) {
        Predicate<String> predicate = string -> string.isEmpty();
        System.out.println(predicate.test(""));
        System.out.println(predicate.test("hoge"));
    }
}
```

```:実行結果
true
false
```

### `isEqual(Object)`

引数で受け取ったオブジェクトと等しいかどうかを判定する新しいPredicateオブジェクトを生成する（比較はObject#equals(Object)メソッドが使用される）。
null セーフになっている。

```java:実装例
package sample;

import java.util.function.Predicate;

public class Sample {
    public static void main(String[] args) {
        Predicate<String> isHoge = Predicate.isEqual("hoge");
        System.out.println(isHoge.test("hoge"));
        System.out.println(isHoge.test("fuga"));

        Predicate<Object> isNull = Predicate.isEqual(null);
        System.out.println(isNull.test(null));
        System.out.println(isNull.test("not null"));
    }
}
```

```:実行結果
true
false
true
false
```

### `and(Predicate<? super T>)`

引数で渡したPredicateオブジェクトをAND条件で連結させた新しいPredicateオブジェクトを生成する。

```java:実装例
package sample;

import java.util.function.Predicate;

public class Sample {
    public static void main(String[] args) {
        Predicate<String> isUpperCase = string -> string.matches("[A-Z]+");
        Predicate<String> isAlphabet  = string -> string.matches("[a-zA-Z]+");

        Predicate<String> predicate = isAlphabet.and(isUpperCase);

        System.out.println(predicate.test("HOGE"));
        System.out.println(predicate.test("hoge"));
    }
}
```

```:実行結果
true
false
```

### `or(Predicate<? super T>)`

引数で渡したPredicateオブジェクトをOR条件で連結させた新しいPredicateオブジェクトを生成する。

```java:実装例
package sample;

import java.util.function.Predicate;

public class Sample {
    public static void main(String[] args) {
        Predicate<String> isUpperCase = string -> string.matches("[A-Z]+");
        Predicate<String> isNumber    = string -> string.matches("\\d+");

        Predicate<String> predicate = isNumber.or(isUpperCase);

        System.out.println(predicate.test("HOGE"));
        System.out.println(predicate.test("1234"));
        System.out.println(predicate.test("hoge"));
    }
}
```

```:実行結果
true
true
false
```

### `negate()`

negate() を実行したPredicateオブジェクトを否定する、新しいPredicateオブジェクトが生成される。

```java:実装例
package sample;

import java.util.function.Predicate;

public class Sample {
    public static void main(String[] args) {
        Predicate<String> isEmpty = string -> string.isEmpty();

        Predicate<String> isNotEmpty = isEmpty.negate();

        System.out.println(isNotEmpty.test("hoge"));
        System.out.println(isNotEmpty.test(""));
    }
}
```

```:実行結果
true
false
```

### `Bi～`
* `BiConsumer\<T,U>`
* `BiFunction\<T,U,R>`
* `BiPredicate\<T,U>`
それぞれ `Consumer\<T>`・`Function\<T, R>`・`Predicate\<T, U>`の抽象メソッドの引数が２つになっている。

## `BinaryOperator<T>`
`BiFunction`の拡張インターフェース。
`T`型の引数を2 つ受け取って`T`型の値を返す`apply(T, T)`メソッドが抽象メソッドとして存在する。
UnaryOperatorでは1つの引数を受け取っていたのに対して、BinaryOperatorは2つの引数を受け取って、引数と同じ型の処理を戻す。

```java:OperatorFactoryクラス
import java.util.function.BinaryOperator;

public class OperatorFactory {
	public static BinaryOperator<Integer> add(){
		return (a,b) -> a+b;
	}

	public static BinaryOperator<Integer> minus(){
		return (a,b) -> a-b;
	}
}
```

```java:Sampleクラス
import java.util.function.BinaryOperator;

public class Sample {
	public static void main(String[] args) {
		BinaryOperator<Integer> op = OperatorFactory.add();
		System.out.println(op.apply(10,20));
	}
}
```
```:実行結果
30
```



### `maxBy(Comparator<? super T>)`

`apply(T, T)`メソッドに渡された２値を、指定した`Comparator`オブジェクトで比較して大きい方の値を返す`BinaryOperator`オブジェクトを生成する。

```java:実装例
package sample;

import java.util.function.BinaryOperator;

public class Sample {
    public static void main(String[] args) {
        BinaryOperator<Integer> maxBy = BinaryOperator.maxBy(Integer::compare);
        int max = maxBy.apply(21, 10);
        System.out.println(max);
    }
}
```

```:実行結果
21
```

### `minBy(Comparator<? super T>)`

```java:実装例
package sample;

import java.util.function.BinaryOperator;

public class Sample {
    public static void main(String[] args) {
        BinaryOperator<Integer> minBy = BinaryOperator.minBy(Integer::compare);
        int min = minBy.apply(21, 10);
        System.out.println(min);
    }
}
```

```:実行結果
10
```

### `To～Function`と`To～BiFunction`
* `ToIntFunction<T>`
* `ToLongFunction<T>`
* `ToDoubleFunction<T>`

それぞれ、`T`型の値を引数に受け取って、プリミティブ型の値を返す`applyAs～(T)`抽象メソッドを持つ。

```java:実装例
package sample;

import java.util.function.ToIntFunction;

public class Sample {
    public static void main(String[] args) {
        ToIntFunction<String> getLength = string -> string.length();
        System.out.println(getLength.applyAsInt("hoge"));
    }
}
```

```:実行結果
4
```

* `ToIntBiFunction<T,U>`
* `ToLongBiFunction<T,U>`
* `ToDoubleBiFunction<T,U>`

それぞれ、`To～Function`の引数が2つになったバージョン。

```java:実装例
package sample;

import java.util.function.ToIntBiFunction;

public class Sample {
    public static void main(String[] args) {
        ToIntBiFunction<Integer, Integer> add = (a, b) -> a + b;
        System.out.println(add.applyAsInt(12, 53));
    }
}
```

```:実行結果
65
```

### `～To***Function`
* `IntToDoubleFunction`
* `DoubleToIntFunction`
* `LongToDoubleFunction`
* `DoubleToLongFunction`
* `IntToLongFunction`
* `LongToIntFunction`

それぞれ`～`を受け取って`***`を返す`applyAs***(～)`メソッドを抽象メソッドとして持つ。

```java:実装例
package sample;

import java.util.function.IntToDoubleFunction;

public class Sample {
    public static void main(String[] args) {
        IntToDoubleFunction function = i -> (double)i;
        System.out.println(function.applyAsDouble(20));
    }
}
```

```:実行結果
20.0
```

### `～To***Function`
* `ObjIntConsumer<T>`
* `ObjLongConsumer<T>`
* `ObjDoubleConsumer<T>`

それぞれ`T`型の値と`～`の値を引数に受け取る`accept(T, ～)`メソッドを抽象メソッドとして持つ。

```java:実装例
package sample;

import java.util.Arrays;
import java.util.List;
import java.util.function.ObjIntConsumer;

public class Sample {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("hoge", "fuga", "piyo");

        forEach(list, (value, index) -> {
            System.out.printf("list[%d] = %s%n", index, value);
        });
    }

    public static <T> void forEach(List<T> list, ObjIntConsumer<T> callback) {
        for (int i=0; i<list.size(); i++) {
            callback.accept(list.get(i), i);
        }
    }
}
```

```:実行結果
list[0] = hoge
list[1] = fuga
list[2] = piyo
```

<table>
  <caption>書式の意味</caption>
  <thead>
    <tr>
      <th>指定子</th>
      <th>対応する型</th>
      <th>説明</th>
    </tr>
  </thead>
  <tr>
    <td>%s</td>
    <td>string</td>
    <td>文字列を出力</td>
  </tr>
  <tr>
    <td>%d</td>
    <td>int</td>
    <td>整数を10進法で出力</td>
  </tr>
  <tr>
    <td>%f</td>
    <td>float</td>
    <td>実数を出力</td>
  </tr>
  <tr>
    <td>%n</td>
    <td>-</td>
    <td>改行</td>
  </tr>
</table>