ミズノブログ

ミズノです。プログラミング・子育て・経年変化するもの など好きなことを雑多に書きます。

Java8 逆引き Stream API

はじめに

Java8の新機能、Stream APIを使い始めてコーディングが格段に楽になりました。 備忘録的にサンプルコードを書き出してみました。少しずつ追加していく予定です。 Javaは使ったことあるけどラムダ式やStream APIはよく知らないという方は、参考にしてみてください。 バリバリ使っている方は、こんな使い方もあるよ!と教えていただけると嬉しいです。

ちなみにオライリー社のJavaによる関数型プログラミング ―Java 8ラムダ式とStreamがとても参考になりました。

【前提条件】Stream APIの説明に使用するオブジェクト

public class Person {
  private String name;
  private int age;
  private List<Person> children;

  public Person(String name){/*...*/}
  public Person(String name, int age){/*...*/}
  public Person(String name, int age, Person... children){/*...*/}
  
  @Override
  public String toString() {/* name(age) [children...] */}
  
  // getter, setter...
}

コレクション、配列、MapをStreamクラスに変換(Arrays#stream,Stream#of)

  // コレクション
  List<String> list = new ArrayList<>();
  Stream<String> listStream = list.stream();

  // 配列
  String[] ary = new String[] {"AA","BB","CC"};
  Stream<String> aryStream1 = Arrays.stream(ary);
  Stream<String> aryStream2 = Stream.of(ary);

  // MAP
  Map<String,String> map = new HashMap<>();
  Stream<Entry<String, String>> mapStream = map.entrySet().stream();

メソッド参照・コンストラクタ参照(Class::method)

  String[] names = new String[] {"Tom","Bob","Alice"};

    Stream.of(names)
      // コンストラクタ参照
      .map(Person::new) // name -> new Person(name)
      // メソッド参照
      .forEach(System.out::println); // person -> System.out.println(person)
      // Tom(0)
      // Bob(0)
      // Alice(0)

Personリストからnameリスト作成(Stream#collect,Collectors#toList)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  List<String> nameList =
    persons.stream()
      .map(Person::getName)
      .collect(Collectors.toList());
 
  nameList.steram().forEach(System.out::println);  
    // "Tom"
    // "Bob"
    // "Alice"

PersonリストからnameのCSV作成(Stream#collect,Collectors#joining)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  String nameCSV =
    persons.stream()
      .map(p -> String.format("\"%s\"", p.getName()))
      .collect(Collectors.joining(","));

  System.out.println(nameCSV);
  // "Tom","Bob","Alice"

Personリストからageの重複なしリスト作成(Stream#distinct)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));
  persons.add(new Person("Mike", 19));

  List<Integer> ageDistinctList =
    persons.stream()
      .map(Person::getAge)
      .distinct()
      .collect(Collectors.toList());
    
  ageDistinctList.stream().forEach(System.out::println);
  // 21
  // 25
  // 19

Personリストをage順にソート(Stream#sorted,Comparator#comparingInt)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("Bob",  25));
  persons.add(new Person("Alice",19));

  persons.stream()
    .sorted(Comparator.comparingInt(Person::getAge))
    .forEach(System.out::println);
    // Alice(19)
    // Tom(21)
    // Bob(25)
    

Personリストをname頭文字でグループ化(Comparator#groupingBy)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom",  21));
  persons.add(new Person("John", 18));
  persons.add(new Person("Jack", 19));

  Map<Object,List<Person>> nameIndex =
    persons.stream()
      .collect(Collectors.groupingBy(p -> p.getName().charAt(0)));

    System.out.println(nameIndex);
    // {J=[John(18), Jack(19)], T=[Tom(21)]}

Personリストからchildrenリスト作成(Stream#flatMap)

  List<Person> persons = new ArrayList<>();
  persons.add(new Person("Tom", 21,
                  new Person("Tomas", 1), 
                  new Person("Tommy", 0)));
  persons.add(new Person("Bob", 25,
                  new Person("Bobby", 2)));
  persons.add(new Person("Alice", 19));

  persons.stream()
    .flatMap(person -> person.getChildren().stream())
    .forEach(System.out::println);
    // Tomas(1)
    // Tommy(0)
    // Bobby(2)