Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.

ゆるふわJava8入門

1.339 Aufrufe

Veröffentlicht am

2016/10/24
ゆるふわJava8入門 @ビズリーチ

Veröffentlicht in: Ingenieurwesen
  • Loggen Sie sich ein, um Kommentare anzuzeigen.

ゆるふわJava8入門

  1. 1. ゆるふわJava8 入門 株式会社ビズリーチ 大内允介
  2. 2. Who Are You? 大内 允介 (おおうち まさゆき) 30歳 Webエンジニア 某メーカー系SIer 5年半  →ビズリーチ 約1年 Java大好きエンジニア
  3. 3. Java’s History ・Java5(2004/05〜2009/10) ・Java6(2006/12〜2013/02) ・Java7(2011/07〜2015/04) ・Java8(2014/03〜2017/09予定) ・Java9 (2017/03〜予定)
  4. 4. What’s Java8? public void java8() { Stream.of("A001", "B001", "AB001", "BA001") .filter(e -> e.startsWith("A")) .forEach(System.out::println); } Question  文字列リスト(A001, B001, AB001, BA001)の中から、 「A」で始まる文字列のみを抽出してコンソールに出力する。 Answer public void java7() { List<String> strs = Arrays.asList("A001", "B001", "AB001", "BA001"); for (String str : strs) { if (str.startsWith("A")) { System.out.println(str); } } } 1年前の僕「えっ、何これ怖い。。。」
  5. 5. Lambda式 メソッド参照 Stream Optional What’s Java8? Comparator<String> comparator = (a, b) -> { Integer.compare(a.length(), b.length()); }; Consumer<String> consumer = System.out::println; List<String> newList = list.stream().filter(e -> e.length() >= 3).collect(Collectors.toList()); Optional<String> langCd = getConfigValue("langCd"); return langCd.orElse("en");
  6. 6. Today’s Goal
  7. 7. Today’s Goal ・Java8の目玉「ラムダ式」「Stream」の基礎が分かる。 ・ラムダ式(->)が怖くなくなる。 ・メソッド参照(::)が怖くなくなる。 ・Streamを触ってみたい、という気になる。 ・なんとなくJavaが好きになる。
  8. 8. What’s Lambda?
  9. 9. () -> { 処理 } // 引数が0個 (str) -> { 処理 } // 引数が1個 str -> { 処理 } // 引数が1個の場合、括弧の省略可 (str, n) -> { 処理 } // 引数が2個の場合 ( 引数 ) -> System.out.println(str); ( 引数 ) -> { System.out.println(str); return n; } What’s Lambda? Comparator<String> comparator = (a, b) -> { Integer.compare(a.length(), b.length()); }; 基本文法: ( 引数 ) -> { 処理 } Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String a, String b) { return Integer.compare(a.length(), b.length()); } }; 慣れるまでは一度Java7で実装してから ラムダ式に直すようにすると覚えやすいかも?IDE頼みという手も。
  10. 10. What’s Functional Interface? ラムダ式やメソッド参照の代入先になれるインターフェース。 実装が必要な抽象メソッドが1つだけ。 関数インターフェース メソッドシグネチャ Function<T, R> R apply(T) Consumer<T> void accept(T) Supplier<R> R get() Predicate<T> boolean test(T) Comparator<T> int compare(T, T)
  11. 11. Function<List<String>, String> function = (list) -> list.isEmpty() ? null : list.get(0); List<String> list = Arrays.asList("A", "B", "C"); String firstElement = function.apply(list); System.out.println(firstElement); What’s “Function”? 引数を一つとって戻り値を返す関数型インターフェース 関数インターフェース メソッドシグネチャ 引数型 → 戻り値型 Function<T, R> R apply(T) T → R BiFunction<T, U, R> R apply(T, U) T × U → R A
  12. 12. What’s “Consumer”? Consumerは消費者。引数を受け、戻り値なしの処理を行うインターフェース。 値を返さないので、基本的に副作用を起こす目的で使用する。 返り値のない(返り値が void の) Functionと思えばOK。 関数インターフェース メソッドシグネチャ 引数型 → 戻り値型 Consumer<T> void accept(T) T → () BiConsumer<T, U> void accept(T, U) T × U → () Consumer<String> hoge = string -> System.out.println("hoge : " + string); Consumer<String> fuga = string -> System.out.println("fuga : " + string); Consumer<String> consumer = hoge.andThen(fuga); consumer.accept("piyo"); hoge : piyo fuga : piyo
  13. 13. What’s “Supplier”? Supplierは供給者。引数なしで何かしらの値を返す関数型インターフェース。 引数なしなので、当然、BiSupplierは存在しない。 関数インターフェース メソッドシグネチャ 引数型 → 戻り値型 Supplier<R> R get() () → R public class Logger { public void log(Level level, Supplier<String> supplier) { if (isLoggable(level) { write(level, supplier.get()); } } } logger.log(Level.INFO, () -> "log message: " + doSomethingMethod()); 記述量を減らせるだけでなく、遅延評価の恩恵も受けられる。
  14. 14. What’s “Predicate”? Predicateは判定を行う為の関数型インターフェース。 引数を一つとり、boolean型の引数を返す。 関数インターフェース メソッドシグネチャ 引数型 → 戻り値型 Predicate<T> boolean test(T) T → boolean BiPredicate<T,U> boolean test(T, U) T × U → boolean Predicate<String> isUpperCase = string -> string.matches("[A-Z]+"); Predicate<String> isAlphabet = string -> string.matches("[a-zA-Z]+"); Predicate<String> predicate = isAlphabet.and(isUpperCase); System.out.println(predicate.test("HOGE")); System.out.println(predicate.test("hoge")); true false
  15. 15. Lambda’s Benefit ? 記述の簡潔化 Comparator<String> comparator = new Comparator<String>() { @Override public int compare(String a, String b) { return Integer.compare(a.length(), b.length()); } }; ラムダ式を前提に導入された新機能(Stream etc.) Comparator<String> comparator = (a, b) -> { Integer.compare(a.length(), b.length()); }; public void java8() { Stream.of("A001", "B001", "AB001", "BA001") .filter(e -> e.startsWith("A")) .forEach(System.out::println); }
  16. 16. What’s Method Reference?
  17. 17. BiFunction<List<String>, String, Boolean> function = (list, str) -> list.add(str); function.apply(list, "A001"); BiFunction<List<String>, String, Boolean> function = List<String>::add; function.apply(list, "A001"); What’s Method Reference? 関数型インターフェースの変数にメソッドそのものを代入することが出来る。 class GenericsExample { static <T> void method(T arg) { } static void test() { Consumer<String> c = GenericsExample::<String> method; } } 戻り値の型を明示的に指定したい場合 基本文法: ClassName::methodName  ※()がつかないことに注意
  18. 18. IntFunction<List<String>> factory = ArrayList::new; List<String> array = factory.apply(10); What’s Constructor Reference? コンストラクターも関数型インターフェースの変数に代入することが出来る。 IntFunction<List<String>> factory = (int n) -> new ArrayList<>(n); List<String> array = factory.apply(10);  基本文法: ClassName::new  ※()がつかないことに注意
  19. 19. What’s Stream?
  20. 20. What’s Stream ? 配列やCollectionなどの集合に対して、何らかの処理(変換や集計)を行う。 // 本を検索 List<Book> books = bookSearcher.select(condition); List<String> titles = books.stream() .filter(book -> book.getPublishYear() > 2001) // 2001年以降に発行された本で絞込み .sorted(Comparator.comparing(Book::getPublishYear)) // 発行年で並び替え .map(Book::getTitle) // 本のタイトルのみを抽出 .collect(Collectors.toList()); // リストに変換 Question 本(Book)の検索結果から、発行年(publishYear)が2001年以降の本を抽出し、 本のタイトル(title)の文字列リストを作る。また、タイトルは発行年順に並び替えること。 Answer
  21. 21. What’s Stream ? // 発行年で並び替え Collections.sort(books, new Comparator<Book>() { @Override public int compare(Book book1, Book book2) { return book1.getPublishYear() - book2.getPublishYear(); } }; // 2001年以降に発行された本で絞込み & 本のタイトルのみを抽出 List<String> titles = new ArrayList<>(); for (Book book : books) { if (book.getPublishYear() >= 2001) { titles.add(book.getTitle()); } } List<String> bookNames = books.stream() .filter(book -> book.getPublishYear() >= 2001) // 2001年以降に発行された本で絞込み .sorted(Comparator.comparing(Book::getPublishYear)) // 発行年で並び替え .map(Book::getTitle) // 本のタイトルのみを抽出 .collect(Collectors.toList()); // リストに変換  
  22. 22. What’s Stream? Stream は大きく分けると中間操作と終端操作に分類される。 Streamの生成 中間操作 終端操作 ①データをStreamに変換(生成) ②中間操作で加工・変換 ③終端操作で新しいデータを生成
  23. 23. Create “Stream” List, Map, Array など様々なデータ形式からStreamを生成可能。 List<String> list = Arrays.asList("hoge", "fuga", "bar"); Stream<String> stream = list.stream(); Stream<String> stream = Arrays.stream(new String[] {"hoge", "fuga"}); Stream<Map.Entry<Integer, String>> stream = map.entrySet().stream(); Builder<String> builder = Stream.builder(); Stream<String> stream = builder.add("hoge").add("fuga").build(); Stream<String> stream = Stream.empty(); Stream<String> stream = Stream.of("hoge", "fuga", "bar", "foo");
  24. 24. try (Stream<String> stream = Files.lines(Paths.get("test.txt"))) { stream.forEach(System.out::println); } catch (IOException e) { // 例外処理 } Stream<Integer> stream = Stream.iterate(1, i -> i + 1).limit(100); // UnaryOperator を引数にとる // => 1, 2, 3, … , 100 Stream<String> stream = Stream.generate(() -> "test").limit(5); // Supplier を引数にとる // => "test", "test", "test", "test", "test" Create “Stream” IntStream stream = IntStream.rangeClosed(1, 100); // => 1, 2, 3, … , 100 テストデータ作りにも便利(実務ではあまり使わないかも?) ファイル操作も便利
  25. 25. Intermediate Operation Streamのデータ加工を行います。 終端操作時にまとめて実行される。つまり、実際にループが行われるのは基本的に1回。 メソッド名 メソッドシグネチャ map Stream<R> map(Function<T, R>) 変換(1:1) filter Stream<T> filter(Predicate<T>) 絞り込み flatMap Stream<R> flatMap(Function<T, Stream<R>) 変換(1:N) distinct Stream<T> distinct() 重複要素の集約 limit Stream<T> limit(long) 要素数の指定 skip Stream<T> skip(long) 要素のスキップ sorted Stream<T> sorted(Comparator<T>) 並び替え peek Stream<T> peek(Consumer<T>) 状態確認(デバッグ目的)
  26. 26. mapメソッドは1:1のデータの変換処理を行う中間操作。 めっちゃよく使う。 引数を1つだけ受け取り、すべての要素に対し同じ処理を行い、戻り値を返します。 What’s “map”? List<String> bookTitles = books.stream() .map(Book::getTitle) // 本のタイトルのみを抽出 .collect(Collectors.toList()); // リストに変換 List<String> bookTitles = books.stream() .map(book -> { return book.getTitle(); } .collect(Collectors.toList()); List<String> prefixList = books.stream() .map(Book::getTitle) // タイトルを取得 .map(title -> title.substring(0,1)); // 1つ目のmapの処理結果を元に頭文字をとる .collect(Collectors.toList()); // リストに変換
  27. 27. What’s “filter”? filterメソッドはPredicate<T>を引数に取り、Streamから条件に一致するものを抽出する中間操作。 これもめっちゃよく使う。 Set<String> bookTitles = books.stream() .map(Book::getTitle) .filter(title -> title.startsWith("A")) // 本のタイトルが「A」で始まるもののみを抽出 .collect(Collectors.toSet()); // リストに変換 List<String> prefixList = books.stream() .filter(book -> book.getPublishYear() >= 2001) // 発行年が2001年以降の本のみを抽出 .map(Book::getTitle) .filter(title -> title.startsWith("A")) // 本のタイトルが「A」で始まるもののみを抽出 .collect(Collectors.toList()); // リストに変換
  28. 28. flatMapメソッドはFunction<T, Stream<R>>を引数に取り、要素TからStream<R>を生成する。 Collectionの中にネストしたCollectionがある場合に使える。 What’s “flatMap”? final int totalStringCount = books.stream() .flatMap(book -> book.getPages().stream()) .collect(Collectors.summingInt(Page::getStringCount)); @Data class Book { String title; Integer publishYear; List<Page> pages; } @Data class Page { String content; Integer stringCount; }
  29. 29. Terminal Operation Streamの全データを一括で別のデータに変換する。 終端操作は1つのStreamに1度しか実行できない。(再利用すると例外が発生する。) メソッド名x メソッドシグネチャ collect R collect(Collector<T,A,R>) 集合化 forEach void forEach(Consumer<T>) 副作用 anyMatch/allMatch/noneMatch boolean anyMatch(Predicate<T>) 条件判定 findAny / findFirst Optional<T> findAny() 任意/最初の要素 count long count() 要素数 max / min Optional<T> max(Comparator<T>) 最大/最小の要素
  30. 30. What’s “collect”? List<Book> books = selectBookList(condition); List<Integer> bookIds = books.stream() .map(Book::getId) .collect(Collectors.toList()); Streamを元に新しいデータ構造に変換する操作。めっちゃ使う。 Map<Integer, Book> bookMapByPublishedYear = books.stream() .collect(Collectors.toMap(Book::getPublishedYear, book -> book)); long booksCount = books.stream().collect(Collectors.counting()); long allStockCount = books.stream().collect(Collectors.summingInt(Book::getStock)); Stream joinedTitle = books.stream() .map(Book::getTitle) .collect(Collectors.joining(", ", "[[", "]]")); // => "[[ABN-10987012, SDX-36107012, YIC-7844401]]"
  31. 31. What’s “forEach”? 従来のfor文にあたるもの。めっちゃ使う。 books.forEach(book -> { book.setDeleteFlg(true); bookUpdater.update(book); System.out.println("[updated] : " + book.getId())); } 処理件数をカウントすることができません。 break; continue; ができない。 欠点: int count = 0; books.forEach(book -> { count++; // <= ここでcountはスコープ外なのでコンパイルエラー System.out.println(book.getId())); }
  32. 32. Stream’s Benefit ? ・ソートや抽出処理が混ざったfor文が簡潔に書ける。 ・並列処理が簡単に使える。(Stream#parallelStream() List<String> bookNames = books.stream() .filter(book -> book.getPublishYear() >= 2001) // 2001年以降に発行された本で絞込み .sorted(Comparator.comparing(Book::getPublishYear)) // 発行年で並び替え .map(Book::getTitle) // 本のタイトルのみを抽出 .collect(Collectors.toList()); // リストに変換 List<String> bookNames = books.parallelStream() .filter(book -> book.getPublishYear() >= 2001) // 2001年以降に発行された本で絞込み .sorted(Comparator.comparing(Book::getPublishYear)) // 発行年で並び替え .map(Book::getTitle) // 本のタイトルのみを抽出 .collect(Collectors.toList()); // リストに変換  →とはいえ、苦手なこともあるので、既存の拡張for文はまだ現役です。
  33. 33. Summary
  34. 34. Summary public void java8() { Stream.of("A001", "B001", "AB001", "BA001") .filter(e -> e.startsWith("A")) .forEach(System.out::println); } Answer Question  文字列リスト(A001, B001, AB001, BA001)の中から、 「A」で始まる文字列のみを抽出してコンソールに出力する。 public void java8() { Stream.of("A001", "B001", "AB001", "BA001") .filter(e -> e.startsWith("A")) } public void java8() { Stream.of("A001", "B001", "AB001", "BA001") } public void java8() { } 「ラムダ式」「Stream」の基礎が分かるようになりましたか?
  35. 35. Summary ・Java8の目玉「ラムダ式」「Stream」の基礎が分かる。 ・ラムダ式(->)が怖くなくなる。 ・メソッド参照(::)が怖くなくなる。 ・Streamを触ってみたい、という気になる。 ・なんとなくJavaが好きになる。

×