徹底解説！Java8特性

皆さん、こんにちは！

最近、仕事を探しています。java エンジンニアとして面接をうける際に、よくjava8の特性の問題を質問されました。
だから、本記事はjava8の特性を中心としてまとめてご解説いたします。

### 一、ラムダ式
この前のjavaバージョンでリストをソートするために、下記のように実装すべきである。

```java
List<String> myList= Arrays.asList("tom", "jack", "smith", "allen");
Collections.sort(myList, new Comparator() { 
  @Override 
  public int compare(String a, String b) { 
    return b.compareTo(a); 
  }
});
```
だが、java8の特性(lambda式)を用いたら、下記のlambda式で簡単に実装できる。

```java
Collections.sort(names, (a, b) -> b.compareTo(a));
```

上記のlambda式で、コードはめっちゃ読みやすいでしょうかね。
なお、a,bの型はjvmにより、自動的に推測できるし、returnキーワードもなくなった。

### 二、Functional Interface
#### Functional Interfaceとは
interfaceの中に一個だけのメソッドがある場合のみ、lambda式に書き換える。
例えば、あるinterfaceは以下のようにします。@FunctionalInterfaceアノテーションをつけると、Functional　Interfaceのことを明らかにする。


```java
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
```
次に、以下のようにlambada式に書き換えましょうか。

```java
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123
```

#### Predicateインターフェース
Predicateとは、引数を指定してboolean型の値を戻すインターフェースである。
下記の使い方をご参考しましょう。

```java
Predicate<String> predicate = (s) -> s.length() > 0;

predicate.test("zoo");              // true
predicate.negate().test("zoo");     // false

Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;

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

```

#### Functionインターフェース
Functionとは、Functionインターフェースを使うと引数に基づいてにインスタンスを戻れます。

```java
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);

backToString.apply("123");     // "123"
```
#### Supplierインターフェース
Supplierとは、Supplierインターフェースを使うと引数を指定せずに、インスタンスを戻れます。

```java
class Person {
    String firstName;
    String lastName;

    Person() {}

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
```
```java
Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person
```
#### Consumerインターフェース
Consumerとは、引数を指定するうえで、次の処理を行う。

```java
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.lastName);
greeter.accept(new Person("Tom", "Smith"));
```

#### Comparatorインターフェース
Comparatorについては、この前にも存在しているけど、java8以降、lamba式に変更されます。

```java
Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0

```

#### Optional
Optionalとは、 Functional Interfaceじゃなくて、NullPointerExceptionを防ぐために、よく使われています。
Optionalの使い方は下記のようにご参考しましょう。

```java
Optional<String> optional = Optional.of("bam");

optional.isPresent();           // true
optional.get();                 // "bam"
optional.orElse("fallback");    // "bam"

optional.ifPresent((s) -> System.out.println(s.charAt(0))); 

```

### 三、Stream API
Streamとは、集合に対する処理機能を提供するAPI。

ここで、説明用のリストを予め作ります。

```java
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
```

#### Filterの使い方
条件を満たすデータしか返らない。

```java
stringCollection
    .stream()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);
// "aaa2", "aaa1"
```

#### Sortedの使い方
Streamにあるデータをソートする。
Comparatorを指定しないとディフォルトのを使います。

```java
stringCollection
    .stream()
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
```

#### Mapの使い方
Streamの中身を変換する。

```java
stringCollection
    .stream()
    .map(String::toUpperCase)
    .forEach(System.out::println);

// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
```
#### Matchの使い方
Streamの中身はある条件にマッチするかどうかを判断する。

```java
// リストの中に先頭が"a"のstringがあるかどうかを判断する。あれば、trueを返す。
boolean anyStartsWithA =
    stringCollection
        .stream()
        .anyMatch((s) -> s.startsWith("a"));

System.out.println(anyStartsWithA);      // true

```
```java
// リストの中にあらゆるデータが"a"で先頭であるかどうかを判断する。
boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch((s) -> s.startsWith("a"));

System.out.println(allStartsWithA);      // false

```

#### Countの使い方
Streamにあるデータの数をカウントする。

```java
long startsWithB =
    stringCollection
        .stream()
        .filter((s) -> s.startsWith("b"))
        .count();

System.out.println(startsWithB);    // 3
```
#### Reduceの使い方
Streamにあるデータを一つにする。

```java
Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
```

### 四、最後に
他には、java8は新たな日付API(ZoneId、LocalDate 、LocalDateTime など)を提供するが、ここで略です。

最後まで読んでいただき、ありがとうございます。