関数型インターフェースのおさらいメモ

# 概要

Java 1.8で導入された関数型インターフェースのおさらいです。

**環境**

* Windows 10 Professional
* OpenJDK 11.0.2

**参考**

* [パッケージjava.util.function] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/function/package-summary.html)
* [Java 8 のイディオム: パススルーに代わる手段] (https://www.ibm.com/developerworks/jp/java/library/j-java8idioms5/index.html)
* [Java 8 のイディオム: カスタム関数型インターフェースを作成する方法を学び、可能な場合は常に組み込み関数型インターフェースを使うべき理由を学ぶ] (https://www.ibm.com/developerworks/jp/java/library/j-java8idioms7/index.html)

# 書き方の簡単なおさらい

このコードでforEachメソッドが受け取っているのがConsumer型の関数型インターフェースです。
この書き方は簡略化されていますが、

```java
List<String> list = List.of("a", "b", "c");
list.forEach(System.out::println);
```

Java 1.8以前の書き方をすれば、次のようになります。

```java
public class PrintLine implements Consumer<Object> {
	@Override
	public void accept(Object t) {
		System.out.println(t);
	}
}
```

```java
List<String> list = List.of("a", "b", "c");
PrintLine println = new PrintLine();
list.forEach(println);
```

また、匿名クラスの書き方にすれば、次のようになります。

```java
List<String> list = List.of("a", "b", "c");
list.forEach(new Consumer<Object>() {
	@Override
	public void accept(Object t) {
		System.out.println(t);
	}
});
```

これらの書き方を、Java 1.8で導入されたラムダ式を使うことで簡略化することができます。

```java
// (1) 匿名クラスの書き方をラムダ式に変えると、このように書けます。
list.forEach((String t) -> {
	System.out.println(t);
});

// (2) 引数の型は自明なので省略できます。
list.forEach((t) -> {
	System.out.println(t);
});

// (3) 引数が1つだけの場合は、引数の()を省略できます。
list.forEach(t -> {
	System.out.println(t);
});

// (4) ブロック内のコードが1行の場合は{}を省略できます。コードのセミコロンも不要です。
list.forEach(t -> System.out.println(t));

// (5) 関数型インターフェースの抽象メソッド（この場合はConsumer.accept）のシグネチャと
// 実行するメソッドのシグネチャが一致している場合はメソッド参照という書き方にすることができます
list.forEach(System.out::println);
```

# [FunctionalInterfaceアノテーション] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/FunctionalInterface.html)

関数型インターフェースには`@FunctionalInterface`アノテーションが付いていますが、

```java
@FunctionalInterface
public interface Consumer<T> {
  //...
}
```

> インタフェース型の宣言を、Java言語仕様に定義されている関数型インタフェースとすることを目的としていることを示すために使われる情報目的の注釈型です。 概念上、1つの関数型インタフェースには抽象メソッドが1つだけあります。 

上記に引用したように、関数型インターフェースの定義を満たす条件は、インターフェースに抽象メソッドが1つだけ宣言されていることです。

> インタフェース宣言にFunctionalInterface注釈型が存在しているかどうかにかかわらず、コンパイラは関数型インタフェースの定義を満たすどのインタフェースも関数型インタフェースとして扱います。

また、この条件を満たせばこのアノテーションの有無に関わらずコンパイラは関数型インターフェースとして扱われます。

# java.util.functionパッケージ

このパッケージには基本的な関数型インターフェースが定義されています。代表的なものでは`Consumer`、`Function`、`Predicate`、`Supplier`があり、これらを特殊化した`IntCounsumer`や`IntFunction`などもあります。
また、このパッケージ外にも特定目的のために実装された関数型インターフェースがあります。

## Consumer (Tからvoidへの単項関数)

> 型パラメータ:
T - オペレーションの入力の型

```java:抽象メソッド
void accept(T t);
```

**BiConsumer**
`Consumer`を特殊化した、2つの引数を受け取る`BiConsumer`という関数型インターフェースもあります。

> 型パラメータ:
T - オペレーションの第1引数の型
U - オペレーションの第2引数の型

```java:抽象メソッド
void accept​(T t, U u);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Iterator\<E\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Iterator.html)

##### forEach

Consumerの使い方でよくみるものにイテレータのforEachメソッドがあります。

```java:Iterable.forEach
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
```

**サンプル**
Java 1.8以降は(1)のような書き方はせず、ラムダ式で(2)または(3)のように書きます。
(2)のように1行でかける場合はブロックで囲む必要がなく(3)のように書けます。
さらに(4)のようにメソッド参照として記述すると、コードを簡略化できます。

```java
List<String> list = List.of("a", "b", "c");

// (1)
list.forEach(new Consumer<String>() {
	@Override
	public void accept(String t) {
		System.out.println(t);
	}
});

// (2)
list.forEach(s -> {
	System.out.println(s);
});

// (3)
list.forEach(s -> System.out.println(s));

// (4) メソッド参照
list.forEach(System.out::println);
```

## Function (TからRへの単項関数)

> 型パラメータ:
T - 関数の入力の型
R - 関数の結果の型

```java:抽象メソッド
R apply(T t);
```

**BiFunction**
`Function`を特殊化した、2つの引数を受け取る`BiFunction`という関数型インターフェースもあります。

> 型パラメータ:
T - 関数の第1引数の型
U - 関数の第2引数の型
R - 関数の結果の型

```java:抽象メソッド
R apply​(T t, U u);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Map\<K,​V\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Map.html)

##### computeIfAbsent

```java:Map.computeIfAbsent
default V computeIfAbsent(K key,
        Function<? super K, ? extends V> mappingFunction) {
    Objects.requireNonNull(mappingFunction);
    V v;
    if ((v = get(key)) == null) {
        V newValue;
        if ((newValue = mappingFunction.apply(key)) != null) {
            put(key, newValue);
            return newValue;
        }
    }

    return v;
}
````

**サンプル**

```java
Map<String, Integer> map = new HashMap<>();

// (1)
Integer value = map.computeIfAbsent("apple", new Function<String, Integer>(){
	@Override
	public Integer apply(String t) {
		return t.length();
	}
});

// (2)
value = map.computeIfAbsent("banana", s -> {
	return s.length();
});

// (3)
value = map.computeIfAbsent("cherry", s -> s.length());

// (4) インスタンスのメソッド参照
value = map.computeIfAbsent("durian", String::length);
```

## UnaryOperator\<T\>

スーパーインターフェースに`Function`を持ち、引数の型と同じ型を返すFunctionを特殊化した関数型インターフェースです。

> 型パラメータ:
T - 演算子のオペランドと結果の型

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [List\<E\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/List.html)

##### replaceAll

```java:List.replaceAll
default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
    while (li.hasNext()) {
        li.set(operator.apply(li.next()));
    }
}
```

**サンプル**

```java
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("cherry");

// (1)
list.replaceAll(new UnaryOperator<String>() {
	@Override
	public String apply(String t) {
		return t.toUpperCase();
	}
});

// (2)
list.replaceAll(t -> t.toUpperCase());

// (3) インスタンスのメソッド参照
list.replaceAll(String::toUpperCase);
```

### UnaryOperator.identity

UnaryOperatorインターフェースにはidentityというstaticメソッドがあります。（Functionインターフェースにもあります。）

```java
static <T> UnaryOperator<T> identity() {
    return t -> t;
}
```

このメソッドの利用例としてよく見るコードでは、下記のようなListをMapに変換するものがあります。
この変換は、mapのキーにItemクラスのidを、mapの値にItemクラスのインスタンスをセットしますが、入力引数を返すidentityメソッドを使うことでコードの意図が明確になります。

```java
List<Item> list = new ArrayList<>();
list.add(new Item(1L, "apple"));
list.add(new Item(2L, "banana"));
list.add(new Item(3L, "cherry"));

//Map<Long, Item> fruitIdMap = list.stream()
//				.collect(Collectors.toMap(Item::getId, i -> i));
// more than better
Map<Long, Item> fruitIdMap = list.stream()
				.collect(Collectors.toMap(Item::getId, UnaryOperator.identity()));

System.out.println(fruitIdMap);
// {1=Item [id=1, name=apple], 2=Item [id=2, name=banana], 3=Item [id=3, name=cherry]}
```

## Predicate (Tからbooleanへの単項関数)

> 型パラメータ:
T - 述語の入力の型

```java:抽象メソッド
boolean test(T t);
```

**BiPredicate**
`Predicate`を特殊化した2つの引数を受け取る`BiPredicate`という関数型インターフェースもあります。

> 型パラメータ:
T - 述語の第1引数の型
U - 述語の第2引数の型

```java:抽象メソッド
boolean test​(T t, U u);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Collection\<E\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Collection.html)

##### removeIf

```java:Collection.removeIf
default boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    boolean removed = false;
    final Iterator<E> each = iterator();
    while (each.hasNext()) {
        if (filter.test(each.next())) {
            each.remove();
            removed = true;
        }
    }
    return removed;
}
```

**サンプル**
listから偶数を取り除くサンプルです。removeIfはListに対して副作用を持つので不変(Immutable)なListの場合はエラーになります。

```java
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);

// (1)
list.removeIf(new Predicate<Integer>() {
	@Override
	public boolean test(Integer t) {
		return t % 2 == 0;
	}
});

// (2)
list.removeIf(t -> {
	return t % 2 == 0;
});

// (3)
list.removeIf(t -> t % 2 == 0);
```

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Optional\<T\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html)

##### filter

```java:Optional.filter
public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent()) {
        return this;
    } else {
        return predicate.test(value) ? this : empty();
    }
}
```

**サンプル**

```java
Optional<Integer> opt = Optional.of(1);

// (1)
Optional<Integer> result = opt.filter(new Predicate<Integer>() {
	@Override
	public boolean test(Integer t) {
		return t % 2 == 0;
	}
});

// (2)
result = opt.filter(t -> {
	return t % 2 == 0;
});

// (3)
result = opt.filter(t -> t % 2 == 0);

result.ifPresentOrElse(System.out::println, () -> {
	System.out.println("it's odd number");
});
// → it's odd number
```

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.regex.Pattern] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/regex/Pattern.html)

##### asPredicate

```java:Pattern.asPredicate
public Predicate<String> asPredicate() {
    return s -> matcher(s).find();
}
```

**サンプル**

```java
Pattern pattern = Pattern.compile("^\\d+$");

List<String> list = List.of("123", "abc", "456", "78d");

List<String> result = list.stream()
						.filter(pattern.asPredicate())
						.collect(Collectors.toList());

result.forEach(System.out::println);
// →　123
// →　456
```

## Supplier (Rへの無限関数)

> 型パラメータ:
T - このサプライヤから提供される結果の型

```java:抽象メソッド
T get();
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Optional\<T\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html)

##### orElseGet

```java:Optional.orElseGet
public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}
```

**サンプル**

```java
Optional<String> fruit = Optional.ofNullable(null);

// (1)
String result = fruit.orElseGet(new Supplier<String>() {
	@Override
	public String get() {
		return "banana";
	}
});

// (2)
result = fruit.orElseGet(() -> {
	return "banana";
});

// (3)
result = fruit.orElseGet(() -> "banana");

// (4) メソッド参照
result = fruit.orElseGet(SupplierDemo::getDefault);
```

```java:SupplierDemo
public static String getDefault() {
	return "banana";
}
```

##### orElseThrow

```java:Optional.orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
```

**サンプル**

```java
Optional<String> fruit = Optional.ofNullable(null);

// (1)
String result = fruit.orElseThrow(new Supplier<RuntimeException>() {
	@Override
	public RuntimeException get() {
		return new FruitNotFoundException();
	}
});

// (2)
result = fruit.orElseThrow(() -> {
	return new FruitNotFoundException();
});

// (3)
result = fruit.orElseThrow(() -> new FruitNotFoundException());

// (4) コンストラクタ参照
result = fruit.orElseThrow(FruitNotFoundException::new);
```

```java:FruitNotFoundException
class FruitNotFoundException extends RuntimeException {
	public FruitNotFoundException() {
		super();
	}
}
```

#### コンストラクタ参照のサンプル

**配列を生成するコンストラクタ参照のサンプル**

```java
List<String> list = List.of("apple", "banana", "cherry", "durian", "elderberry");
// String[] fruits = list.toArray(size -> new String[size]);
// more than better?
String[] fruits = list.toArray(new String[0]);
```

上記のコレクションを配列に変換するコードは、コンストラクタ参照で書くと下記のようになります。

```java
List<String> list = List.of("apple", "banana", "cherry", "durian", "elderberry");
String[] fruits = list.toArray(String[]::new);
```

#### [java.logging] (https://docs.oracle.com/javase/jp/11/docs/api/java.logging/module-summary.html) : [java.util.logging.Logger] (https://docs.oracle.com/javase/jp/11/docs/api/java.logging/java/util/logging/Logger.html)

##### log

```java:Logger.log
public void log(Level level, Supplier<String> msgSupplier) {
    if (!isLoggable(level)) {
        return;
    }
    LogRecord lr = new LogRecord(level, msgSupplier.get());
    doLog(lr);
}
```

# java.util.functionパッケージ以外

バージョン1.8以前からあるインターフェースですが、関数型インターフェースの条件を満たすため、ラムダ式またはメソッド参照の代入先として使用できます。

## [FileFilter] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/io/FileFilter.html)

```java:抽象メソッド
boolean	accept​(File pathname);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [File] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/io/File.html)

##### listFiles

```java:File.listFiles​
public File[] listFiles(FileFilter filter) {
    String ss[] = list();
    if (ss == null) return null;
    ArrayList<File> files = new ArrayList<>();
    for (String s : ss) {
        File f = new File(s, this);
        if ((filter == null) || filter.accept(f))
            files.add(f);
    }
    return files.toArray(new File[files.size()]);
}
```

**サンプル**

```java
File directory = new File("D:\\temp");
Long limit = 1024L * 1024L * 7L;

File[] overLimitFiles = directory.listFiles(pathname -> pathname.length() > limit);
```

## [Runnable] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/lang/Runnable.html)

```java:抽象メソッド
void run();
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.util.Optional\<T\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Optional.html)

##### ifPresentOrElse

```java
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
    if (value != null) {
        action.accept(value);
    } else {
        emptyAction.run();
    }
}
```

**サンプル**

```java
Optional<String> opt = Optional.ofNullable(null);
opt.ifPresentOrElse(s -> {
	System.out.println(s);
},() -> {
	System.out.println("null");
});
```

## [PathMatcher] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/nio/file/PathMatcher.html)

```java:抽象メソッド
boolean	matches​(Path path);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [java.nio.file.FileSystem] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/nio/file/FileSystem.html)

##### getPathMatcher

```java:FileSystem.getPathMatcher
public abstract PathMatcher getPathMatcher(String syntaxAndPattern);
```

**サンプル**

記事の主題からそれますが、`getPathMatcher`メソッドに渡す値はSyntaxとPatternをコロン(:)で区切った文字列になります。
Syntaxに"glob"を指定した場合はPatternに正規表現に似たより単純なパターンを指定でき、また"regex"を指定した場合はPatternに正規表現を指定できます。

```java
FileSystem fileSystem = FileSystems.getDefault();
PathMatcher matcher = fileSystem.getPathMatcher("glob" + ":" + "**/*.java");

Path path = Paths.get("D:", "temp");
try {
	Files.walk(path).filter(matcher::matches).forEach(System.out::println);
} catch (IOException e) {
	throw new UncheckedIOException(e);
}
```

## [Comparator\<T\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Comparator.html)

このインターフェースには`compare`の他に`boolean equals​(Object obj)`という抽象メソッドが宣言されていますが、以下に引用したとおり

> インタフェースが、java.lang.Objectのpublicメソッドの1つをオーバーライドする抽象メソッドを宣言する場合も、それはインタフェースの抽象メソッド数に反映されません。理由は、そのインタフェースのいずれかの実装にjava.lang.Objectまたは他の場所からの実装が含まれるからです。

関数型インターフェースとしての条件を満たしています。

```java:抽象メソッド
int compare(T o1, T o2);
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [Collections] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Collections.html)

##### min

```java:Collections.min
@SuppressWarnings({"unchecked", "rawtypes"})
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
    if (comp==null)
        return (T)min((Collection) coll);

    Iterator<? extends T> i = coll.iterator();
    T candidate = i.next();

    while (i.hasNext()) {
        T next = i.next();
        if (comp.compare(next, candidate) < 0)
            candidate = next;
    }
    return candidate;
}
```

**サンプル**

JobクラスのPriority、Idを昇順でソートし最小のJobを返すサンプルです。
なお、下記に引用するようにコレクションの要素数が多い場合はコストがかかります。

> このメソッドはコレクション全体で反復処理を行うので、コレクションのサイズに比例した時間が必要です。

```java
List<Job> list = List.of(
	// Id, Priority
	new Job(1L, 3),
	new Job(2L, 3),
	new Job(3L, 2),
	new Job(4L, 1),
	new Job(5L, 1),
	new Job(6L, 2)
);

// (1)
Job minJob = Collections.min(list, new Comparator<Job>() {
	@Override
	public int compare(Job j1, Job j2) {
		if (Objects.equals(j1.getPriority(), j2.getPriority())) {
			return Long.compare(j1.getId(), j2.getId());
		}
		return Integer.compare(j1.getPriority(), j2.getPriority());
	}
});
System.out.println(minJob);
// → Job [id=4, priority=1]

// (2)
minJob = Collections.min(list, Comparator.comparing(Job::getPriority).thenComparing(Job::getId));
System.out.println(minJob);
// → Job [id=4, priority=1]
```

## [Callable\<V\>] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/concurrent/Callable.html)

```java:抽象メソッド
V call() throws Exception;
```

### JDKでの利用例

#### [java.base] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/module-summary.html) : [ExecutorService] (https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/concurrent/ExecutorService.html)

##### submit

```java:ExecutorService.submit
<T> Future<T> submit(Callable<T> task);
```

**サンプル**

```java
ExecutorService service = Executors.newSingleThreadExecutor();

// (1)
Future<LocalDateTime> future = service.submit(new Callable<LocalDateTime>() {
	@Override
	public LocalDateTime call() throws Exception {
		TimeUnit.SECONDS.sleep(5L);
		return LocalDateTime.now();
	}
});

/*
// (2)
Future<LocalDateTime> future = service.submit(() -> {
    TimeUnit.SECONDS.sleep(5L);
    return LocalDateTime.now();
});
*/

LocalDateTime result = future.get();
service.shutdown();
```