Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Option(al)が教えてくれたいろんな言語を知る楽しさ(というかひたすらOptionの解説)

 Option(al)が教えてくれたいろんな言語を知る楽しさ(というかひたすらOptionの解説)

Java女子部「Java x Scala交流会」

Fb025419ed38f98df595eb2eafc859f4?s=128

ihcomega56

May 13, 2017
Tweet

Transcript

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

  2. だれ • こな(@ihcomega) Java女子部の部長 明後日から会社が変わるよー 5月は春の登壇祭り!遊びに来てね JJUG CCC 2017 Spring

    文系さえおさえれば英語を読む力は上がる! マチコ&河村の怒り新党 Java Day Tokyo 2017 Heather VanCura x Java女子部 ~海外と日本のエンジニア事情~ スペシャルパネルセッション - 海外Javaコミュニティ・エンジニア は今どんな活動をしているのか?
  3. Java / Scalaエンジニアのみなさんと Option(al)をきっかけに 考え方を共有 = 交流 してみたいです! + 私が思ったことをお伝えします!

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

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

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

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

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

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

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

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

  12. 使うシーンを想定

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

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

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

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

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

  18. 定義 イラストに登場したものたちをクラスで 定義してみる /** ຊ */ case class Book(title: String)

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

    /** ຊ୨ */ case class BookShelf(book: Option[Book]) /** Ո */ case class House(bookShelf: Option[BookShelf]) 家に本棚がある かもしれない 本棚に本がある かもしれない
  20. インスタンス生成 本と本棚を用意しておく /** ίοϓຊ */ val scalaBook = Book("ίοϓຊ") /**

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

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

    ۭͷຊ୨͕͋ΔՈ */ val houseWithEmptyShelf = House(Some(BookShelf(None))) /** ຊ୨ͷͳ͍Ո */ val emptyHouse = House(None) つまり こういうこと
  23. いよいよ値を取り出したり使ったりします。 よくわからない書き方や関数が出てくるかも しれませんが、操作のイメージを掴んでく ださい。

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

    Optionの中身を変換する イメージ
  25. 「取り出して使うイメージ」 の方からいきます。

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

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

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

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

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

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

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

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

    emptyHouse .bookShelf .get } ないかな?
  34. それ 結局nullチェックと同じやん != null とか == null とか

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

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

  37. Option#getOrElse // ຊͷஔ͔Εͨຊ୨ fullShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") res0: String = ίοϓຊ 本が存在したので タイトルを

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

  39. Option#getOrElse // ۭͷຊ୨ emptyShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") res0: String = σϑΥϧτλΠτϧ None 本が存在しないので

    デフォルト値を 返せた! 本棚にある本のタイトルを取り出してみる
  40. // ຊͷஔ͔Εͨຊ୨ fullShelf.book match { case Some(b) => s"ʮ${b.title}ʯͱ͍͏ຊͩΑʂ" case

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

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

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

    None => "λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ" } res0: String = λΠτϧ͕ݟ͔ͭΒͳ͍Αʼʻ パターンマッチ 本が存在するので Noneの場合の 結果が返された! 本棚にある本のタイトルを取り出してみる
  44. 「Optionの中身を変換するイメージ」 の方いきます。

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

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

    Someインスタンスとして タイトルが返された!
  47. fullShelf.book.map(_.title) Option#map λΠτϧ λΠτϧ Option Option 本棚にある本をタイトルに変換してみる

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

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

  50. Option#map // ۭͷຊ୨ emptyShelf.book.map(_.title) res0: Option[String] = None 本が存在しないので Noneオブジェクトが

    返された! 本棚にある本をタイトルに変換してみる
  51. Option#flatMap 家にある本棚を本に変換してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book)

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

    Someインスタンスとして 本が返された!
  53. houseWithFullShelf.bookShelf.flatMap(_.book) Option#flatMap Option Option Option Option 家にある本棚を本に変換してみる

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

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

  56. // ۭͷຊ୨͕͋ΔՈ houseWithEmptyShelf.bookShelf.flatMap(_.book) Option#flatMap res0: Option[Book] = None 本が存在しないので Noneオブジェクトが

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

  58. // ຊ୨ͷͳ͍Ո emptyHouse.bookShelf.flatMap(_.book) Option#flatMap res0: Option[Book] = None 本棚が存在しないので Noneオブジェクトが

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

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

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

    b.title } }
  62. 本棚にある本を条件でフィルタしてみる // ຊͷஔ͔Εͨຊ୨ fullShelf.book.filter(_.title.length > 3) Option#filter res0: Option[Book] =

    Some(Book(ίοϓຊ)) 条件に合ったため Someインスタンスとして 本が返された!
  63. // ຊͷஔ͔Εͨຊ୨ fullShelf.book.filter(_.title.length <= 3) Option#filter res0: Option[Book] = None

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

    本が存在しないので Noneオブジェクトが 返された! 本棚にある本を条件でフィルタしてみる
  65. // ຊͷஔ͔Εͨຊ୨ fullShelf.book.foreach(b => println(b.title)) Option#foreach ίοϓຊ 本が存在するため foreachに渡した処理が 実行された!

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

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

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

  69. 家から本棚を取り出してみる // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.get Option#get相当 // ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.getBookShelf().get(); 似ている isDefined相当のisPresentもある

    前述したのと同じ理由で あまり使わないはず
  70. 本棚にある本のタイトルを取り出してみる // ۭͷຊ୨ emptyShelf.getBook().map(b -> b.getTitle()).orElse(“σϑΥϧτλΠτϧ"); // ۭͷຊ୨ emptyShelf.book.map(_.title).getOrElse("σϑΥϧτλΠτϧ") Option#getOrElse相当

    orElseというメソッド なおScalaのOptionにも orElseがあるが挙動は違う
  71. Option#filter相当 // ຊͷஔ͔Εͨຊ୨ fullShelf.getBook().filter(b -> b.getTitle().length() <= 3); // ຊͷஔ͔Εͨຊ୨

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

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

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

    ຊͷஔ͔Εͨຊ୨͕͋ΔՈ houseWithFullShelf.bookShelf.flatMap(_.book) 似ている
  75. パターンマッチ相当 ない?

  76. for式相当 ない?

  77. 感想:大体似てたw

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