Slide 1

Slide 1 text

Option(al)が教えてくれた いろんな言語を知る楽しさ (というかひたすらOptionの解説) 2017.05.13 Java女子部 Java x Scala交流会

Slide 2

Slide 2 text

だれ • こな(@ihcomega) Java女子部の部長 明後日から会社が変わるよー 5月は春の登壇祭り!遊びに来てね JJUG CCC 2017 Spring 文系さえおさえれば英語を読む力は上がる! マチコ&河村の怒り新党 Java Day Tokyo 2017 Heather VanCura x Java女子部 ~海外と日本のエンジニア事情~ スペシャルパネルセッション - 海外Javaコミュニティ・エンジニア は今どんな活動をしているのか?

Slide 3

Slide 3 text

Java / Scalaエンジニアのみなさんと Option(al)をきっかけに 考え方を共有 = 交流 してみたいです! + 私が思ったことをお伝えします!

Slide 4

Slide 4 text

java.util.Optional 使ってますか? 何故この概念が便利か知ってますか?

Slide 5

Slide 5 text

Optionalと私 Java SE 8が出た当初、勉強してみたけど正直よく分 からなかった。 (「包む」「くるむ」「ラップする」の意味が分からずw) 理解する前に、Java離れを起こした。 大して触ったことのないまま放置!!!

Slide 6

Slide 6 text

scala.Option Javaで言うとOptionalに近いもの。 当たり前のように使われる!

Slide 7

Slide 7 text

Optionと私 実務でたくさん使った。 手を動かすことで便利さを実感し、身についた。 (本当はSwiftのOptionalもそうなんだけど今日は触れません…) 再び向き合い、理解出来た!

Slide 8

Slide 8 text

早速ScalaのOptionを紹介します!

Slide 9

Slide 9 text

Optionとは 存在するか分からない値を表現する ある ない OR

Slide 10

Slide 10 text

Optionとは 存在するか分からない値を表現する Scala.Some インスタンス None オブジェクト OR

Slide 11

Slide 11 text

例を使って考えてみましょう。

Slide 12

Slide 12 text

使うシーンを想定

Slide 13

Slide 13 text

使うシーンを想定 家がある

Slide 14

Slide 14 text

使うシーンを想定 家がある 家に本棚がある かもしれない

Slide 15

Slide 15 text

使うシーンを想定 家がある 家に本棚がある かもしれない 本棚に本がある かもしれない

Slide 16

Slide 16 text

使うシーンを想定 家がある 家に本棚がある かもしれない 本棚に本がある かもしれない ここで、 家の中にある本棚や本を扱う ことを考えてみる!

Slide 17

Slide 17 text

まずは必要なものを揃えましょう!

Slide 18

Slide 18 text

定義 イラストに登場したものたちをクラスで 定義してみる /** ຊ */ case class Book(title: String) /** ຊ୨ */ case class BookShelf(book: Option[Book]) /** Ո */ case class House(bookShelf: Option[BookShelf])

Slide 19

Slide 19 text

定義 イラストに登場したものたちをクラスで 定義してみる /** ຊ */ case class Book(title: String) /** ຊ୨ */ case class BookShelf(book: Option[Book]) /** Ո */ case class House(bookShelf: Option[BookShelf]) 家に本棚がある かもしれない 本棚に本がある かもしれない

Slide 20

Slide 20 text

インスタンス生成 本と本棚を用意しておく /** ίοϓຊ */ val scalaBook = Book("ίοϓຊ") /** ຊͷஔ͔Εͨຊ୨ */ val fullShelf = BookShelf(Some(scalaBook)) /** ۭͷຊ୨ */ val emptyShelf = BookShelf(None)

Slide 21

Slide 21 text

インスタンス生成 3種類の家インスタンスを生成してみる /** ຊͷஔ͔Εͨຊ୨͕͋ΔՈ */ val houseWithFullShelf = House(Some(fullShelf)) /** ۭͷຊ୨͕͋ΔՈ */ val houseWithEmptyShelf = House(Some(emptyShelf)) /** ຊ୨ͷͳ͍Ո */ val emptyHouse = House(None)

Slide 22

Slide 22 text

インスタンス生成 Optionの入れ子構造を確認しておく /** ຊͷஔ͔Εͨຊ୨͕͋ΔՈ */ val houseWithFullShelf = House(Some(BookShelf(Some(scalaBook)))) /** ۭͷຊ୨͕͋ΔՈ */ val houseWithEmptyShelf = House(Some(BookShelf(None))) /** ຊ୨ͷͳ͍Ո */ val emptyHouse = House(None) つまり こういうこと

Slide 23

Slide 23 text

いよいよ値を取り出したり使ったりします。 よくわからない書き方や関数が出てくるかも しれませんが、操作のイメージを掴んでく ださい。

Slide 24

Slide 24 text

値を扱う方法 Option#get Option#getOrElse パターンマッチ Option#map Option#flatMap for式 ※ここにあるのは一部。他にも色々ある。 取り出して使う イメージ Optionの中身を変換する イメージ

Slide 25

Slide 25 text

「取り出して使うイメージ」 の方からいきます。

Slide 26

Slide 26 text

Option#get 家から本棚を取り出してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.get

Slide 27

Slide 27 text

家から本棚を取り出してみる Option#get // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.get res0: BookShelf = BookShelf(Some(Book(ίοϓຊ))) 取り出せた!

Slide 28

Slide 28 text

家から本棚を取り出してみる Option#get // ۭͷຊ୨͕͋ΔՈ houseWithEmptyShelf.bookShelf.get

Slide 29

Slide 29 text

家から本棚を取り出してみる Option#get // ۭͷຊ୨͕͋ΔՈ houseWithEmptyShelf.bookShelf.get res0: BookShelf = BookShelf(None) 取り出せた!

Slide 30

Slide 30 text

家から本棚を取り出してみる Option#get // ຊ୨͕ͳ͍Ո emptyHouse.bookShelf.get

Slide 31

Slide 31 text

家から本棚を取り出してみる Option#get // ຊ୨͕ͳ͍Ո emptyHouse.bookShelf.get java.util.NoSuchElementException: None.get 取り出せない!

Slide 32

Slide 32 text

家から本棚を取り出してみる Option#isDefined if (emptyHouse.bookShelf.isDefined) { emptyHouse.bookShelf.get } else { // ུ } あるかな?

Slide 33

Slide 33 text

家から本棚を取り出してみる Option#isEmpty if (emptyHouse.bookShelf.isEmpty) { // ུ } else { emptyHouse .bookShelf .get } ないかな?

Slide 34

Slide 34 text

それ 結局nullチェックと同じやん != null とか == null とか

Slide 35

Slide 35 text

Option#getの問題 安全に使うにはSomeであることを担保する必要が ある チェック漏れが発生したら死亡する 実行時までエラーに気付けない (つまりnullチェックと同じ問題を持ったまま・・・)

Slide 36

Slide 36 text

Option#getOrElse 本棚にある本のタイトルを取り出してみる // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") Some(“コップ本”) mapについては後述

Slide 37

Slide 37 text

Option#getOrElse // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") res0: String = ίοϓຊ 本が存在したので タイトルを 取り出せた! Some(“コップ本”) 本棚にある本のタイトルを取り出してみる

Slide 38

Slide 38 text

Option#getOrElse // ۭͷຊ୨ emptyShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") None 本棚にある本のタイトルを取り出してみる

Slide 39

Slide 39 text

Option#getOrElse // ۭͷຊ୨ emptyShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") res0: String = σϑΥϧτλΠτϧ None 本が存在しないので デフォルト値を 返せた! 本棚にある本のタイトルを取り出してみる

Slide 40

Slide 40 text

// ຊͷஔ͔Εͨຊ୨ fullShelf.book match { case Some(b) => s"ʮ${b.title}ʯͱ͍͏ຊͩΑʂ" case None => "λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ" } パターンマッチ 本棚にある本のタイトルを取り出してみる

Slide 41

Slide 41 text

// ຊͷஔ͔Εͨຊ୨ fullShelf.book match { case Some(b) => s"ʮ${b.title}ʯͱ͍͏ຊͩΑʂ" case None => "λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ" } res0: String = ʮίοϓຊʯͱ͍͏ຊͩΑʂ 本が存在するので Someの場合の 結果が返された! パターンマッチ 本棚にある本のタイトルを取り出してみる

Slide 42

Slide 42 text

// ۭͷຊ୨ emptyShelf.book match { case Some(b) => s"ʮ${b.title}ʯͱ͍͏ຊͩΑʂ" case None => "λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ" } パターンマッチ 本棚にある本のタイトルを取り出してみる

Slide 43

Slide 43 text

// ۭͷຊ୨ emptyShelf.book match { case Some(b) => s"ʮ${b.title}ʯͱ͍͏ຊͩΑʂ" case None => "λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ" } res0: String = λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ パターンマッチ 本が存在するので Noneの場合の 結果が返された! 本棚にある本のタイトルを取り出してみる

Slide 44

Slide 44 text

「Optionの中身を変換するイメージ」 の方いきます。

Slide 45

Slide 45 text

Option#map 本棚にある本をタイトルに変換してみる // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title) 参考 map(b => b.title) とも書ける

Slide 46

Slide 46 text

本棚にある本をタイトルに変換してみる Option#map // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title) res0: Option[String] = Some(ίοϓຊ) 本が存在したので Someインスタンスとして タイトルが返された!

Slide 47

Slide 47 text

fullShelf.book.map(_.title) Option#map λΠτϧ λΠτϧ Option Option 本棚にある本をタイトルに変換してみる

Slide 48

Slide 48 text

fullShelf.book.map(_.title) Option#map λΠτϧ map λΠτϧ Option Option 本棚にある本をタイトルに変換してみる

Slide 49

Slide 49 text

Option#map // ۭͷຊ୨ emptyShelf.book.map(_.title) 本棚にある本をタイトルに変換してみる

Slide 50

Slide 50 text

Option#map // ۭͷຊ୨ emptyShelf.book.map(_.title) res0: Option[String] = None 本が存在しないので Noneオブジェクトが 返された! 本棚にある本をタイトルに変換してみる

Slide 51

Slide 51 text

Option#flatMap 家にある本棚を本に変換してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book)

Slide 52

Slide 52 text

家にある本棚を本に変換してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book) Option#flatMap res0: Option[Book] = Some(Book(ίοϓຊ)) 本棚・本が存在したので Someインスタンスとして 本が返された!

Slide 53

Slide 53 text

houseWithFullShelf.bookShelf.flatMap(_.book) Option#flatMap Option Option Option Option 家にある本棚を本に変換してみる

Slide 54

Slide 54 text

家にある本棚を本に変換してみる houseWithFullShelf.bookShelf.flatMap(_.book) Option#flatMap flatMap Option Option Option

Slide 55

Slide 55 text

// ۭͷຊ୨͕͋ΔՈ houseWithEmptyShelf.bookShelf.flatMap(_.book) Option#flatMap 家にある本棚を本に変換してみる

Slide 56

Slide 56 text

// ۭͷຊ୨͕͋ΔՈ houseWithEmptyShelf.bookShelf.flatMap(_.book) Option#flatMap res0: Option[Book] = None 本が存在しないので Noneオブジェクトが 返された! 家にある本棚を本に変換してみる

Slide 57

Slide 57 text

// ຊ୨ͷͳ͍Ո emptyHouse.bookShelf.flatMap(_.book) Option#flatMap 家にある本棚を本に変換してみる

Slide 58

Slide 58 text

// ຊ୨ͷͳ͍Ո emptyHouse.bookShelf.flatMap(_.book) Option#flatMap res0: Option[Book] = None 本棚が存在しないので Noneオブジェクトが 返された! 家にある本棚を本に変換してみる

Slide 59

Slide 59 text

flatMap x map 家の本棚を本のタイトルに変換してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book).map(_.title)

Slide 60

Slide 60 text

家の本棚を本のタイトルに変換してみる for式 // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ for { shelf <- houseWithFullShelf.bookShelf book <- shelf.book } yield { book.title }

Slide 61

Slide 61 text

for式の意味を紐解く for式 houseWithFullShelf.bookShelf.flatMap { bs => bs.book.map { b => b.title } }

Slide 62

Slide 62 text

本棚にある本を条件でフィルタしてみる // ຊͷஔ͔Εͨຊ୨ fullShelf.book.filter(_.title.length > 3) Option#filter res0: Option[Book] = Some(Book(ίοϓຊ)) 条件に合ったため Someインスタンスとして 本が返された!

Slide 63

Slide 63 text

// ຊͷஔ͔Εͨຊ୨ fullShelf.book.filter(_.title.length <= 3) Option#filter res0: Option[Book] = None 条件に合わないため Noneオブジェクトが 返された! 本棚にある本を条件でフィルタしてみる

Slide 64

Slide 64 text

// ۭͷຊ୨ emptyShelf.book.filter(_.title.length > 3) Option#filter res0: Option[Book] = None 本が存在しないので Noneオブジェクトが 返された! 本棚にある本を条件でフィルタしてみる

Slide 65

Slide 65 text

// ຊͷஔ͔Εͨຊ୨ fullShelf.book.foreach(b => println(b.title)) Option#foreach ίοϓຊ 本が存在するため foreachに渡した処理が 実行された! 本棚にある本のタイトルがあるときだけ 処理してみる

Slide 66

Slide 66 text

// ۭͷຊ୨ emptyShelf.book.foreach(b => println(b.title)) Option#foreach 本が存在しないため foreachに渡した処理が 実行されない! 本棚にある本のタイトルがあるときだけ 処理してみる

Slide 67

Slide 67 text

注意 今回はわかりやすいように fullShelf(常にSome[Book]を持つ) emptyShelf(常にNoneを持つ) などを用意しただけで、普通は分けない。 1つのOption型変数が状況により SomeになったりNoneになったりするのだ ということをお忘れなく!

Slide 68

Slide 68 text

ここからはJava! ここまでやったことをJavaで書くとどうなる か考えてみました。 アドバイスや間違いの指摘お願いします! ※必要なクラスの定義は割愛しますが、各クラスにgetterを 用意しました。

Slide 69

Slide 69 text

家から本棚を取り出してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.get Option#get相当 // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.getBookShelf().get(); 似ている isDefined相当のisPresentもある 前述したのと同じ理由で あまり使わないはず

Slide 70

Slide 70 text

本棚にある本のタイトルを取り出してみる // ۭͷຊ୨ emptyShelf.getBook().map(b -> b.getTitle()).orElse(“σϑΥϧτλΠτϧ"); // ۭͷຊ୨ emptyShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") Option#getOrElse相当 orElseというメソッド なおScalaのOptionにも orElseがあるが挙動は違う

Slide 71

Slide 71 text

Option#filter相当 // ຊͷஔ͔Εͨຊ୨ fullShelf.getBook().filter(b -> b.getTitle().length() <= 3); // ຊͷஔ͔Εͨຊ୨ fullShelf.book.filter(_.title.length <= 3) 似ている 本棚にある本を条件でフィルタしてみる

Slide 72

Slide 72 text

Option#foreach相当 // ຊͷஔ͔Εͨຊ୨ fullShelf.getBook().ifPresent(b -> System.out.println(b.getTitle())); // ຊͷஔ͔Εͨຊ୨ fullShelf.book.foreach(b => println(b.title)) 本棚にある本のタイトルがあるときだけ 処理してみる foreachはないけど ifPresentを使って 同様の処理が実現できる

Slide 73

Slide 73 text

Option#map相当 本棚にある本をタイトルに変換してみる // ຊͷஔ͔Εͨຊ୨ fullShelf.getBook().map(b -> b.getTitle()); // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title) 似ている

Slide 74

Slide 74 text

家にある本棚を本に変換してみる Option#flatMap相当 // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.getBookShelf() .flatMap(b -> b.getBook()); ほぼおなじ // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book) 似ている

Slide 75

Slide 75 text

パターンマッチ相当 ない?

Slide 76

Slide 76 text

for式相当 ない?

Slide 77

Slide 77 text

感想:大体似てたw

Slide 78

Slide 78 text

さいごに ある言語で分からなかったこと、挫折したことも、 違う言語で再挑戦すると理解できることがある 考え方を理解すれば、多少仕様やAPIが違っても すぐ馴染める 2つ以上の言語を比べると、特徴が見えてくる 言語によって出来ること・出来ないことがあるが、 それを把握することで開発する際に留意すべき 点が分かるような気がする 色々な言語に挑戦するといいことが…!