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

わたしがみんなにオススメするBetter JavaとしてのScala

わたしがみんなにオススメするBetter JavaとしてのScala

脱!老害

Kazumune Katagiri

June 25, 2016
Tweet

More Decks by Kazumune Katagiri

Other Decks in Technology

Transcript

  1. ࣗݾ঺հ • ยۅ Ұफ(͔ͨ͗Γ ͔ͣΉͶ) • id:nemuzuka / @nemuzuka •

    Java / JavaScript / Scala • ݸਓࣄۀओ(vss.jp.net)
  2. ࢲ͕Scalaਪ͠ͳཧ༝ • ੩తܕ෇͚ • IDEΛ࢖ͬͯιʔεΛ௥͍΍͍͢ɻίϯύΠϧ࣌ʹΤϥʔݕ஌ɻ҆৺ʂ • Javaͷ࢓༷(JavaEEͱ͔)ʹԊͬͯͯ΋҆৺ײ͕ແ͘ͳ͖ͬͯͨ • JavaEE࣮ߦ؀ڥͷબ୒ࢶ… •

    ݁ہSpring BootͰे෼͡ΌͶʁͰ΋ɺSpringͷόʔδϣϯUPͷ௥ै΋πϥϛ͋Γͦ͏… • ͦ΋ͦ΋ʮJavaʯͩͱएऀͷ৯͍͖͕ͭྑ͘ͳ͍ؾ͕͢Δ(͋͘·Ͱݸਓͷײ૝Ͱ͢) • هड़ྔΛগͳ͘͢Δ͜ͱ͕Ͱ͖Δ • ͍ΖΜͳॴʹࢄΒ͹ΔࣅͨΑ͏ͳ৑௕ͳॲཧΛ؆୯ʹॻ͘͜ͱ͕Ͱ͖Δ • ΤϥʔΛى͜͠ʹ͍͘هड़Λ͠΍͘͢ͳΔ
  3. ࡯ͯ͘͠Ε·͢ -- java String hoge = “NDS48"; Map<Long, String> map

    = new HashMap<>(); map.put(1L, "NDS#48"); MapͬͯݴͬͯΔͷʹɺHashMapͷهड़λϧΠ... ม਺ଆʹܕΛॻ͔ͳͯ͘ࡁΉɻ1ߦͷίʔυهड़ݮΔɻ LLͬΆ͘ॻ͚Δ͚Ͳܕ҆શɻ طʹ༻ҙ͞Ε͍ͯΔϥΠϒϥϦΛ࢖͏ͱ͖ͷهड़ྔ͸ݮΔ (AWSͱ͔) -- scala var hoge = "NDS48" var map = Map[Long,String]() map += 1L -> “NDS#48” var map2 = Map(1L -> "NDS#48") →ॳظ஋͕͋Ε͹Mapͷܕఆٛ͸ෆཁ
  4. ϝιουఆٛʹ͸Ҿ਺ͷܕ͸ඞཁ def max(x:Int, y:Int):Int = { if (x > y)

    { x } else { y } Ҿ਺໊:ܕ ݁Ռܕ ໌ࣔతʹreturnॻ͔ͳͯ͘΋݁ՌΛฦ͢
  5. Ͱ΋ɺ͍Ζ͍ΖলུͰ͖ΔΜͰ͢ def max(x:Int, y:Int):Int = { if (x > y)

    { x } else { y } } def max(x:Int, y:Int):Int = { if (x > y) x else y } def max(x:Int, y:Int):Int = if (x > y) x else y def max(x:Int, y:Int) = if (x > y) x else y ͱ͸͍͑ɺpublicͳϝιουͷ݁Ռܕ͸লུ͠ͳ͍ํ͕࢖͏ਓʹ༏͍͜͠ͱ͕ଟ͍σε 1ߦͰऩ·ΔifจͷதׅހলུՄ 1ߦͰऩ·Δϝιουͷ தׅހলུՄ ݁ՌܕলུՄ
  6. val:࠶୅ೖ͕Ͱ͖ͳ͍ var:࠶୅ೖ͕Ͱ͖Δ val a = "hoge" // a = “NGT48”

    //ίϯύΠϧΤϥʔ ︙ ௕͍ίʔυ ︙ →͜͜Ͱ͸ɺa==“hoge”ΛอূͰ͖Δ var a = "hoge" a = “NGT48” //͜͏͍͏ॲཧ͕ॻ͚Δ ︙ ௕͍ίʔυ ︙ →͜͜Ͱ͸ɺa==“hoge”ΛอূͰ͖ͳ͍ ௕͍ίʔυͷதͰaͷࢀরઌ͕ มߋ͞ΕΔՄೳੑ͕͋Δ valͰ͋Ε͹ɺଞͷॴͰઈରʹมߋ͞Ε͍ͯͳ͍ͱ໌ݴͰ͖ΔΑ͏ʹͳΔ →ιʔείʔυͰલఏ৚݅Λ୲อͰ͖ɺσʔλͷෆ࣮֬ੑΛഉআ͢Δ͜ͱ͕Ͱ͖Δ valΛ࢖͑͹όά͕ى͖ʹ͘͘ͳΔɻ҆৺ʂ
  7. if͸஋Λฦ͢ͷͰɺແཧͳ͘val var fileName = "default.txt" if(!args.isEmpty) fileName = args(0) ͜ͷॻ͖ํͩͱ࠶୅ೖͷඞཁ͕͋Δҝ

    ม਺fileName͸varͰͳ͍ͱ͍͚ͳ͍ val fileName = if(!args.isEmpty) args(0) else “default.txt" ม਺fileNameʹval͕࢖͑Δʂ҆৺ʂ ex.) ը໘͔Β୯Ձ͕ೖྗ͞Εͨ৔߹ɺͦͷ஋ɻ ະೖྗͷ৔߹ɺ঎඼Ϛελ͔Β୯ՁΛܭࢉͯ͠ઃఆ val unitPrice = if(inputUnitPrice.nonEmpty) BigDecimal(inputUnitPrice) else { ʙ঎඼ϚελΛࢀরͯ͠୯ՁΛܭࢉ͢Δॲཧʙ } ͜ͷifจ͸ ୯Ձܾఆʹؔ͢Δॲཧͷ͔ͨ·Γ(unitPriceͷ஋Λઃఆ͢Δॲཧ) ͩͱ༰қʹ૝૾͕ͭ͘(͍͍ͪͪؔ਺ʹ֎ग़͠͠ͳͯ͘΋ߦؒΛಡΈऔΓ΍͍͢)
  8. immutable(ෆม) / mutable(มߋՄೳ) • ओʹSet΍List(ScalaͰ͸SeqͷαϒΫϥε)΍MapΛ࢖͏࣌ʹؾʹ͢Δ • Javaͷjava.util.ArrayList΍java.util.HashMap͸mutable • ཁૉͷมߋ͕Ͱ͖Δ(෭࡞༻Λ࣋ͬͯ͠·͏) •

    Scalaͷscala.List͸immutable • ཁૉͷมߋ͕Ͱ͖ͳ͍(෭࡞༻Λ࣋ͨͳ͍) ཁૉͷมߋ͕Ͱ͖ͳ͍ˠଞͷॴͰઈରʹมߋ͞Ε͍ͯͳ͍ͱ໌ݴͰ͖Δ immutableΛ࢖͑͹όά͕ى͖ʹ͘͘ͳΔɻ҆৺ʂ
  9. ϒϩοΫࣜΛ࢖͏ͱ͜Μͳײ͡ val map = { val m = Map.newBuilder[Long, String]

    m += 1L -> "Hoge" m += 2L -> "Hage" m += 3L -> "Hige" ɾɾɾ m.result() } ϒϩοΫࣜͷதͰ mutableͳMapʹରͯ͠มߋ͠·͢ (DB౳͔Βऔಘͨ͠σʔλΛ ઃఆ͢Δॲཧͱ͔Λهड़͢ΔΠϝʔδ) ͜ΕͰม਺ʮmapʯ͸ valͰimmutableͳMapʹͳΔɻ҆৺ʂ Ͱɺ࠷ޙʹimmutableͳMapʹม׵͢Δ
  10. immutableͳΦϒδΣΫτΛ ؆୯ʹੜ੒Ͱ͖·͢ • ίϯετϥΫλʹࢦఆ͞ΕͨҾ਺͸val෇͖ͱͯ͠ѻ͏ • ಡΈऔΓઐ༻ʹͳΔˠimmutableʂ҆৺ʂDTOʹ࠷దʂ • Πϯελϯεੜ੒࣌ʮnewʯΩʔϫʔυ͍Βͳ͍ʂָνϯʂ • toString/hashCode/equals͕ࣗಈͰ࣮૷͞ΕΔʂcase

    classಉ࢜Λʮ==ʯͰൺֱͰ͖ΔΑ͏ʹͳΔʂ • copyϝιου͕༻ҙ͞ΕΔˠϓϩύςΟͷҰ෦Λมߋͯ͠৽͍͠ΦϒδΣΫτΛ࡞Δ͜ͱ͕؆୯ʹʂ • ͜Ε͚ͩͷػೳ͕classͷલʹʮcaseʯ෇͚Δ͚ͩͰوํͷ΋ͷʹʂੜ࢈ੑUPͰϚωʔδϟʔ΋ϗΫϗΫʂ case class People(name:String, birthday:LocalDate) ͨͩ͠ɺcase class͸case classΛܧঝ͢Δ͜ͱ͕Ͱ͖ͳ͍ͷͰ஫ҙ͕ඞཁσε
  11. tuple • ෳ਺ͷσʔλΛ1ͭͷ͔ͨ·Γͱͯ͠ѻ͑Δ • ܕ͕ҟͳΔෳ਺ͷ໭Γ஋Λฦؔ͢਺͕ॻ͚Δʂ • Θ͟Θ͟໭Γ஋༻ͷclassΛఆٛ͠ͳͯ͘΋ࡁΉʂָνϯʂ val pair =

    (99, "NDS#48") pair._1 → 99 pair._2 →”NDS#48" ʮ_1ʯͷΑ͏ʹ ॱ൪Λࢦఆͯ͠ΞΫηεͰ͖Δ val (num, str) = (99, "NDS#48") ม਺ʹ֨ೲ͢Δ͜ͱ΋Ͱ͖Δ →ͬͪ͜ͷํ͕ಡΈ΍͍͢ ͱ͸ݴ͑ɺσʔλ͕ͨ͘͞Μ͋Δ৔߹͸ ໭Γ஋༻ͷclassΛ࡞ͬͨํ͕ݟ௨͕͠ྑ͘ͳΔͱࢥ͏
  12. for͸͍Ζ͍Ζ࢖͑·͢ val strs = Seq("a", "b", "c") for(str <- strs)

    { //ॱ൪ʹstrʹ஋͕ೖͬͯΔ } ͙Δ͙Δ·Θ͢(JavaͰݴ͏֦ுfor) val strs = Seq("a", "b", "c") for((str, index) <- strs.zipWithIndex) { //strʹ͸ཁૉɺindex͸index } JavaͰ͍͏֦ுforͷ index(Կ൪໨ͷཁૉ͔)΋औಘͰ͖·͢ʂ val strs = Seq("a", "b", "", "d") for(str <- strs if str.nonEmpty) { //“a”,”b”,”d”ͷ࣮࣌ߦ͞ΕΔ } ۭจࣈ͡Όͳ͍΍͚ͭͩॲཧର৅ʹ͍ͨ͠ʂ val strs = Seq("a", "b", "c") val newStrs = for(str <- strs) yield { "new:" + str } →newStrs͸৽͘͠࡞ΒΕͨList list͔Β৽͍͠listΛ࡞Γ·͠ΐ͏ (for͕݁ՌΛฦ͠·͢)
  13. match ͸ switch case ͷڧྗ൛ • ஋ʹΑͬͯॲཧΛ෼͚Δ͜ͱ͕Ͱ͖Δ • จࣈྻ΍਺஋ͷൺֱ͸΋ͪΖΜɺܕͰൺֱ͢Δ͜ͱ΋Ͱ͖Δ •

    Α͘ݟΔͷ͸Option͔Β஋Λऔͬͯ͘Δ࣌ s match { case "abc" => 1 case "def" => 2 case _ => 3 } break͸ෆཁ defaultͷcase͸”_” val result = s match { case "abc" => 1 case "def" => 2 case _ => 3 } ஋Λฦ͢͜ͱ΋Ͱ͖Δ n match { case m if m < 0 => "ෛ਺" case 0 => "zero" case m if m <= 3 => "3ҎԼ" case _ => "ͨ͘͞Μ" } ৚݅΋ॻ͚Δ
  14. ໊લ෇͖Ҿ਺ • ίϯετϥΫλ΍ϝιουͷҾ਺ΛఆٛॱͰͳ͘ɺҾ਺໊Ͱࢦఆ͢Δ͜ͱ͕Ͱ͖Δ • Ҿ਺ͷॱ൪ͷมߋʹ΋ڧ͍ • ݺͼग़͠ݩͷهड़͕ཧղ͠΍͍͢ʂ • ಉ͡ܕ͕3ͭ͘Β͍ͷϝιουͩͱ໊લ෇͖Ҿ਺ͷํ͕͏Ε͍͠ʂ •

    ஋͕ࢦఆ͞Ε͍ͯͳ͍࣌Λڐ༰͢Δ࣌͸ɺॳظ஋΋ࢦఆͰ͖Δɻָνϯʂ save(entity, true, false, true) save(isAdmin = true, isParent = false, isRefresh = true, target = entity) ex. ) def save(target:People, isAdmin:Boolean, isParent:Boolean, isRefresh:Boolean) ͲͪΒ΋ݺͼग़ͤΔɻԼͷ΄͏͕Boolean͕ԿΛҙຯ͢Δ͔Θ͔Γ΍͍͢
  15. nullΛฦ͢ઃܭͷฐ֐… /** * idʹඥͮ͘Ϩίʔυ͕ଘࡏͨ͠৔߹ɺͦͷDTO * ଘࡏ͠ͳ͍৔߹ɺnull */ People get(Long id);

    People people = get(id); String name = people.name; nullνΣοΫ͠ͳ͍ͱɺψϧϙ͕ग़Δ͔΋ Կ͔݁ՌΛฦ͢ॲཧΛॻ࣌͘ɺॲཧͰ͖ͳ͔ͬͨ࣌ʹnullΛฦ͢ઃܭͨ͜͠ͱ͸͋Γ·ͤΜ͔ʁ ͦͷΑ͏ͳ৔߹ɺݺͼग़͠ݩͰnullνΣοΫΛ͠ͳ͍ͱ ࣮ߦ࣌ʹNullPointerException͕throw͞ΕΔՄೳੑ͕͋Γ·͢ɻ People people = get(id); String name = “”; if(people != null) { name = people.name } -- java -- ָ؍తͳώτ -- Χλ͘
  16. ͞Α͏ͳΒ NullPointerExceptionʂ /** * idʹඥͮ͘Ϩίʔυ͕ଘࡏͨ͠৔߹ɺSome[People] * ଘࡏ͠ͳ͍৔߹ɺNone */ def get(id:Long):Option[People]

    val peopleOpt = get(id) val name = peopleOpt match { case Some(people) => people.name case None => “” } ScalaͰ͸nullͱܾผ͢ΔͨΊʹʮOptionʯʹ͘ΔΜͰฦ͢͜ͱΛ͠·͢ɻ (Java8͔Β΋OptionalͰ࣮ݱͰ͖·͕͢…) Option͔Β஋ΛऔΓग़͢ॲཧΛߦ͏ͷͰ Noneͷ࣌ͷॲཧΛҙࣝ͠ͳ͚Ε͹ͳΒͳ͍
  17. ༗Δ/ແ͠Ͱͳ͘ɺ΋͏গ͠ৄࡉͳ ৘ใ͕ཉ͍͠৔߹͸Eitherܕ def getInputStream(filePath:String):Either[Exception , FileInputStream] ࣦഊ࣌:Left→ࣦഊͨ͠ཧ༝౳ ੒ޭ࣌:Right ※͜ͷϝιουͷ݁Ռ͸ɺLeft or

    Rightʹ͘ΔΜͰฦ͢ඞཁ͕͋Γ·͢ getInputStream(“hoge.csv”) match { case Left(e) => //͜͜ʹདྷΔͱ͖͸ɺࣦഊ࣌ɻม਺eʹException͕ଋറ͞ΕΔ case Right(is) => //͜͜ʹདྷΔͱ͖͸ɺਖ਼ৗऴྃ࣌ɻม਺inʹFileInputStream͕ଋറ͞ΕΔ } ྫ֎ൃੜ࣌͸ɺ͜Μͳײ͡ʹ͢ΔͷͰɺScalaͰ͸ExceptionΛthrow͢Δػձ͸ݮΓ·͢ try ʙ catchΛॻ͔ͳͯ͘ࡁΉͷͰɺݟͨ໨εοΩϦʂ
  18. OptionΛ࢖͍͸͡ΊΔͱ… 1. AςʔϒϧʹҾ਺ͷid͕߹க͢ΔϨίʔυ͕͋Ε͹࣍ͷॲཧ΁ɺແ͚Ε͹None →funcA 2. ʮ1ʯͷϨίʔυͷதʹސ٬ID͕ઃఆ͞Ε͍ͯΕ͹࣍ͷॲཧ΁ɺແ͚Ε͹None 3. ʮ2ʯͷސ٬IDʹඥͮ͘1೥ؒͷച্Λूܭ͠໭Γ஋ͱͯ͠Optionʹ͘ΔΜͰฦ͢ →funcC Έ͍ͨͳॲཧ͸ɺ

    val result = funcA(id) match { case Some(record) => record.customerId match { case Some(customerId) => funcC(customerId) case _ => None } case _ => None //funcAͷॲཧͰσʔλ͕ແ͔ͬͨ࣌ͷ໭Γ஋ } ؒҧͬͯͳ͍͚Ͳɺωετ͕ଟ͍͠ɺ funcAͷॲཧݺͼग़͠Ͱσʔλ͕͋Δ / ແ͍࣌ͷهड़͕཭ΕͯͯݟͮΒ͍… →ωετ͕͞Βʹਂ͘ͳΔ or தͷॲཧ͕௕͘ͳΔ΄ͲݟͮΒ͘ͳΔ
  19. લఏ৚݅Λશͯຬ͚ͨͨ࣌ͩ͠ ॲཧΛ͍ͨ͠৔߹͸ɺforࣜ val result = for { record <- funcA(id)

    customerId <- record.customerId } yield funcC(customerId) ͦΕͧΕ͕NoneͰͳ͍࣌ʹyieldͷॲཧ͕࣮ߦ͞ΕΔ ม਺resultʹ͸ Option(funcCͷ໭Γ஋) or None͕ઃఆ͞ΕΔ ͘͢͝εοΩϦʂϝϯς͠΍͍͢ʂ
  20. ·ͱΊ • όάͷग़ʹ͍͘ιʔείʔυΛॻͨ͘Ίͷखஈͱͯ͠Scalaͷ࿩Λ͠·ͨ͠ • val Ͱ immutableͳΦϒδΣΫτΛѻ͑ΔΑ͏ʹͳͬͯ͘Δͱɺόάͷग़ʹ ͍͘ιʔείʔυʹͳ͍͖ͬͯ·͢ • ௕͘อक্͍ͯ͘͠Ͱվम͕ॏͳΓɺʮ୭ͩʁ͜͜ʹखΛೖΕౕͨ͸ʁʯ

    ͕ൃੜ͢Δස౓ΛݮΒͤΔͱࢥ͍·͢ • ΋ͪΖΜɺJavaͰ΋lombok࢖͑͹Ͱ͖Δ͔΋͠Ε·ͤΜ͕… • WebΞϓϦͷαʔόαΠυ͸ԿͰ΋ྑ͍΍ɺͱ͍͏͜ͱͰ͋Ε͹ɺෆࣗ༝ ͞ͱҾ͖׵͑ʹܕ҆શͳόάͷग़ʹ͍͘ιʔείʔυɺॻ͍ͯΈ·ͤΜ͔ʁ