皆さん、こんにちは!
最近、仕事を探しています。java エンジンニアとして面接をうける際に、よくjava8の特性の問題を質問されました。
だから、本記事はjava8の特性を中心としてまとめてご解説いたします。
一、ラムダ式
この前の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式で簡単に実装できる。
Collections.sort(names, (a, b) -> b.compareTo(a));
上記のlambda式で、コードはめっちゃ読みやすいでしょうかね。
なお、a,bの型はjvmにより、自動的に推測できるし、returnキーワードもなくなった。
二、Functional Interface
Functional Interfaceとは
interfaceの中に一個だけのメソッドがある場合のみ、lambda式に書き換える。
例えば、あるinterfaceは以下のようにします。@FunctionalInterfaceアノテーションをつけると、Functional Interfaceのことを明らかにする。
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
次に、以下のようにlambada式に書き換えましょうか。
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
Predicateインターフェース
Predicateとは、引数を指定してboolean型の値を戻すインターフェースである。
下記の使い方をご参考しましょう。
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インターフェースを使うと引数に基づいてにインスタンスを戻れます。
Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("123"); // "123"
Supplierインターフェース
Supplierとは、Supplierインターフェースを使うと引数を指定せずに、インスタンスを戻れます。
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
Supplier<Person> personSupplier = Person::new;
personSupplier.get(); // new Person
Consumerインターフェース
Consumerとは、引数を指定するうえで、次の処理を行う。
Consumer<Person> greeter = (p) -> System.out.println("Hello, " + p.lastName);
greeter.accept(new Person("Tom", "Smith"));
Comparatorインターフェース
Comparatorについては、この前にも存在しているけど、java8以降、lamba式に変更されます。
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の使い方は下記のようにご参考しましょう。
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。
ここで、説明用のリストを予め作ります。
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の使い方
条件を満たすデータしか返らない。
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
// "aaa2", "aaa1"
Sortedの使い方
Streamにあるデータをソートする。
Comparatorを指定しないとディフォルトのを使います。
stringCollection
.stream()
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1
Mapの使い方
Streamの中身を変換する。
stringCollection
.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
Matchの使い方
Streamの中身はある条件にマッチするかどうかを判断する。
// リストの中に先頭が"a"のstringがあるかどうかを判断する。あれば、trueを返す。
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
// リストの中にあらゆるデータが"a"で先頭であるかどうかを判断する。
boolean allStartsWithA =
stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
Countの使い方
Streamにあるデータの数をカウントする。
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3
Reduceの使い方
Streamにあるデータを一つにする。
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 など)を提供するが、ここで略です。
最後まで読んでいただき、ありがとうございます。