Java8のStream APIのforEachやfillterやmapやsortedやcollectの使い方
Java8からjava.util.stream.Streamというコレクションを便利に操作するクラスができました。
・forEach
今まではコレクションをループする時はfor文や拡張for文を使用していましたが、forEachを使えば簡単に記述することができるようになります。
Listのstreamを取得してforEachでループする例です。
1 2 3 4 5 6 7 8 9 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); list.stream().forEach(s -> System.out.println(s)); } } |
・allMatch
各要素に対して全てが条件を満たすならtrueを返し、そうでなければfalseを返します。
Listのstreamを取得してallMatchで走査する例です。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); boolean flg = list.stream().allMatch(s -> s.contains("C")); System.out.println(flg); } } |
・anyMatch
allMatchに対して、各要素の一つでも条件を満たすならtrue、全ての要素が条件を満たさないならfalseを返します。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); boolean flg = list.stream().anyMatch(s -> s.contains("C")); System.out.println(flg); } } |
・filter
filterはその名の通り、条件を満たす要素のみにフィルタリングします。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); list.stream().filter(s -> s.contains("C")) .forEach(System.out::println); } } |
・map
mapは各要素を別の型に変換してくれます。以下はString型の各要素をInteger型に変換している例です。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("2","4","3","02"); list.stream().map(Integer::parseInt) .forEach(System.out::println); } } |
mapで変換処理をしますが、以下は2倍にする例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import java.util.function.Function; import java.util.stream.Stream; public class Stream005 { public static void main(String[] args) { Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5); Function<Integer, Integer> mapping = e -> e * 2; Stream<Integer> ret = stream.map(mapping); ret.forEach((e)->{ System.out.println(e); }); } } |
・mapToInt
・sum
オブジェクトをプリミティブ型に変換するメソッドです。以下はプリミティブ型に変換してsumメソッドで合計している例です。
1 2 3 4 5 6 7 8 9 10 11 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("2","4","3","02"); int count = list.stream().mapToInt(Integer::parseInt) .sum(); System.out.println(count); } } |
・distinct
各要素で重複している要素を取り除くメソッドです。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("C","C++","C","Java","java"); list.stream().distinct() .forEach(System.out::println); } } |
・sorted
各要素を昇順にソートします。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<String> list = Arrays.asList("3","2","8","4","1"); list.stream().sorted() .forEach(System.out::println); } } |
降順でソートするにはComparatorを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Stream { public static void main(String[] args) { List<String> ret = Stream.of("3", "2", "8" ,"4" , "1") .sorted(Comparator.reverseOrder()) // 降順にするにはsortedに引数が必要 .collect(Collectors.toList()); ret.forEach((e)->{ System.out.println(e); }); } } |
・peek
peekは中間操作です。終端操作があって初めて評価されますが、peek自体はどういう値が入っているかなどを調べたい場合に使うメソッドです。
1 2 3 4 5 6 7 8 9 10 |
import java.util.Arrays; import java.util.List; public class Sample { public static void main(String[] args) { List<Integer> list = Arrays.asList(3,2,8,4,1); list.stream().filter(i -> i > 3).peek(x -> System.out.println(x)) .count(); } } |
・collect
collectメソッドは色々中間操作をしたのちに最終的にコレクションを返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class Sample001 { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); List<String> ret = list.stream().filter((r) -> {return !r.equals("a");}).collect(Collectors.toList()); System.out.println(ret); ret.forEach(s -> System.out.println(s)); } } |
結果は以下のようになります。
1 2 3 4 |
[b, c, d] b c d |
Collectors.joining
collectメソッドのに引数にCollectors.joining(“区切り文字”)を指定することで、文字列連結することができます。
これはコレクションがStringの場合に限ります。
1 2 3 4 5 6 7 8 9 10 |
import java.util.stream.Collectors; import java.util.stream.Stream; public class Stream { public static void main(String[] args) { Stream<String> stream = Stream.of("1", "2", "3", "4", "5"); String i = stream.collect(Collectors.joining("-")); // ハイフン区切りで連結する System.out.println(i); } } |
結果は以下のようになります。
1 |
1-2-3-4-5 |
Collectors.groupingBy
Collectors.groupingByメソッドを使うことによってグルーピングすることができます。
以下は文字列長が同じ文字列でグルーピングする例です。
1 2 3 4 5 6 7 8 9 10 11 |
import java.util.stream.Collectors; import java.util.stream.Stream; public class Stream { public static void main(String[] args) { Stream<String> stream = Stream.of("aiu", "eo", "eeee", "eeaa", "ai", "aiu", "a", "aio"); // 文字列長でグルーピングする stream.collect(Collectors.groupingBy(String::length)).forEach((k,v) -> { System.out.println(k + " = " + v); }); } } |
結果は以下のようになります。
1 2 3 4 |
1 = [a] 2 = [eo, ai] 3 = [aiu, aiu, aio] 4 = [eeee, eeaa] |
forEach外にある変数をforEach内で参照する
forEachの外にある変数をforEach内で使用することはできません。
以下のように配列にしてあげると参照できるのですが良いコーディングではないと思います。
1 2 3 4 5 6 7 |
List<String> list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); String[] arr = {"C"}; list.stream().forEach(s -> { if (s.equals(arr[0])) { System.out.println(s); } }); |
finalで定数にするとforEach内で参照することが可能になりますのでそちらの使い方の方が良いかもしれません。
1 2 3 4 5 6 7 |
List<String> list = Arrays.asList("C", "C++", "Java", "Scala", "Ruby"); final String str = "C"; list.stream().forEach(s -> { if (s.equals(str)) { // 正しく参照できる System.out.println(s); } }); |
Stream.concatメソッドでリスト同士をマージする
リスト同士をStream.concatメソッドでマージすることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Stream { public static void main(String[] args) { List<String> list1 = new ArrayList<>(); list1.add("test1"); list1.add("test2"); List<String> list2 = new ArrayList<>(); list2.add("test1"); list2.add("test2"); list2.add("test3"); List<String> ret = Stream.concat(list1.stream(),list2.stream()) .sorted() .collect(Collectors.toList()); ret.forEach((e)->{ System.out.println(e); }); } } |
重複した結果が返ります。
1 2 3 4 5 |
test1 test1 test2 test2 test3 |
limitで件数を絞る
limitメソッドで件数を指定します。引数はlong型なので3Lというように最後にLを付けます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class Stream { public static void main(String[] args) { List<String> ret = Stream.of("3", "2", "8" ,"4" , "1") .sorted().limit(3L) // 昇順でソートして3件だけにする .collect(Collectors.toList()); ret.forEach((e)->{ System.out.println(e); }); } } |
ソートされた結果を3件だけにしています。
1 2 3 |
1 2 3 |
forEachで引数を複数指定する
ListのListのstreamだとforEach((k,v) -> ~というように複数指定することができます。
1 2 3 |
List<Integer> list = Arrays.asList(1,2,3); Map<Integer, List<Integer>> ret = list.stream().collect(Collectors.groupingBy(n -> n%2)); ret.forEach((k, v) -> System.out.println(k + ":" + v); |
KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^