ã¿ãªããããã«ã¡ã¯ãèã®ç©´ã©ãã®H.Kã§ãã
Java 14ã®ãªãªã¼ã¹ã2020/03ã«äºå®ããã¦ããã¾ãããä»åã¯ããã«å
ã®ãªãªã¼ã¹ã§å
¥ãã¨è¨ããã¦ããSealed Types
ã¨ããæ©è½ã詳ããè¦ã¦ããã¾ãã
Sealed Types
ã¨èãã¦æåã«æãããã¨ã¯ãKotlinã§ãä¼¼ããããªæ©è½ï¼Sealed Class
ï¼ããããã¨ãããã¨ã ã£ãã®ã§Kotlinã®æ©è½ã¨ã®æ¯è¼ãéãã¦å
å®¹ãæ´çã§ãããã¨æãã¾ãã
Sealed Typesã¨ã¯
大ã¾ããªè¨ãæ¹ããã¦ãã¾ãã°ãç¶æ¿å
ãå¶éã§ããæ©è½ã§ãã
詳細ã«ã¤ãã¦ã¯ä»¥ä¸ã®JEPã«è¨è¼ãããã¾ãã
å·çæç¹ï¼2020/02ï¼ã§ã¯Previewã¨ãªã£ã¦ããããããã®æ©è½ãå©ç¨ããããã«ã¯javac
ãå®è¡ããéã«--enable-preview
ãªãã·ã§ã³ãã¤ãã¦æå¹åããå¿
è¦ãããã¾ãã
JEPã®Motivationï¼åæ©ï¼ã®å
容ã確èªããã¨ä»¥ä¸ã®ãããªãã¨ãè¿°ã¹ããã¦ãã¾ãã
å®è£
è
ãç¹å®ã®ç¶æ¿å
ãæ³å®ãã¦å®è£
ãã¦ãã¦ããç¾å¨ã®Javaã®åã·ã¹ãã ã§ã¯å¶éã§ãã¾ãããçµæã¨ãã¦ãç¶æ¿å
ãæ£ç¢ºã«åæãããã¨ãã§ãããã¾ããå©ç¨è
ãèªç±ã«ï¼ãããã¯åæã«ï¼ç¶æ¿å
ãå¢ããã¦ãã¾ããã¨ã«ããã確å®ãªå®è£
ãé£ãããªããã¨ããããããSealed Types
ã®å°å
¥ãæ¨ããããã¨ãã¦ãã¾ãã
ã¾ãããã®Sealed Types
ã¨records
ãç¨ãããã¨ã§ãAlgebraic data type
ï¼ä»£æ°çãã¼ã¿åï¼ã¨å¼ã°ãããã¨ãå¤ããã¼ã¿æ§é ãå½¢æã§ãããã¨ã«ã触ãããã¦ãã¾ãã
Algebraic data typeã¯é¢æ°åããã°ã©ãã³ã°ã§è¯ãå©ç¨ããããã¼ã¿æ§é ã§ãã
JEPã¨ã¯
JDK Enhancement-Proposalã®ç¥ã§ãç´è¨³ããã¨ãJDKã®æ¡å¼µææ¡ãã¨ãªãã¾ããJDKã«æ°æ©è½ã追å ããéã®ç®¡çåä½ãJEPã§ããã¤ã¾ããJEPã追ã£ã¦ããã°è¿½å ãããã§ãããæ©è½ããããã¾ãã
Kotlinã®Sealed Class
Kotlinã§ã¯ããã§ã«Sealed Classã¨ãããã®ãå©ç¨ã§ãã¾ãã
åããã¡ã¤ã«å
ã§ããç¶æ¿ã§ããªãããã«ããä»çµã¿ãKotlinã®Sealed Classã§ãã
kotlinlang.org
Kotlinã§é常ã®ç¶æ¿ãè¡ãå ´åãopen
ãã¤ãã¦ç¶æ¿å¯è½ãªã¯ã©ã¹ã§ãããã¨ãæç¤ºãã¦å®ç¾©ãã¾ãã
// main/kotlin/NotSealedClassesSample.kt open class ExprOpen data class ConstOpen(val number: Double) : ExprOpen() // ExprOpenãç¶æ¿ãã¦å®ç¾©ããã¯ã©ã¹ data class SumOpen(val e1: ExprOpen, val e2: ExprOpen) : ExprOpen() // ExprOpenãç¶æ¿ãã¦å®ç¾©ããã¯ã©ã¹ object NotANumberOpen : ExprOpen() // ExprOpenãç¶æ¿ãã¦å®ç¾©ããã¯ã©ã¹
ä¸è¨ã§ä½æããã¯ã©ã¹ã¯whenå¼
ãªã©ã§å©ç¨ãããã¨ãã§ãã¾ãã
whenå¼
ã¨ã¯Javaã§è¨ãswitchæ
ãå¼ï¼å¤ãè¿ãå½¢å¼ï¼ã¨ãã¦å©ç¨ã§ããããã«ãããã®ã§ãã
ãªããJavaã§ã14ããæ°æ©è½ã¨ãã¦Switch Expressionsï¼ï¼switchãå¼ã§æ±ããããã«ããã¨ããJEPï¼ããªãªã¼ã¹ãããäºå®ã§ãã
ç¶æ¿ããã¯ã©ã¹ãå©ç¨ããç°¡åãªå®è£ ãç¨æãã¦å®è¡ãã¦ã¿ã¾ãã
// main/kotlin/Main.kt fun main(args: Array<String>) { println(eval(ConstOpen(120.0))) // 120.0 println(eval(SumOpen(ConstOpen(10.0), ConstOpen(20.0)))) // 30.0 println(eval(NotANumberOpen)) // NaN } fun eval(expr: ExprOpen): Double = when(expr) { is ConstOpen -> expr.number is SumOpen -> eval(expr.e1) + eval(expr.e2) // åèµ·çã«å¼ã³åºãã¦å¤ãåå¾ãã is NotANumberOpen -> Double.NaN else -> Double.NaN // ç¶æ¿å¯¾è±¡ãçµãè¾¼ããªãã®ã§elseãå¿ è¦ } // openãªã®ã§å¥ãã¡ã¤ã«ã§ã®ç¶æ¿ãå¯è½ data class Multiply(val e1: ExprOpen, val e2: ExprOpen) : ExprOpen()
open
ã使ã£ãé常ã®ç¶æ¿ã«å¯¾ãã¦ãSealed Classã§ç¶æ¿å
ã¨ãªãã¯ã©ã¹ã使ãã¾ããï¼ãµã³ãã«ã³ã¼ãã®ã³ãã¼ã§ããï¼
// main/kotlin/SealedClassesSample.kt sealed class Expr data class Const(val number: Double) : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr()
å
ã»ã©ã®å®è£
ãsealed
ã§å®ç¾©ããç¶æ¿é¢ä¿ãå©ç¨ãã¦æ¸ãæãã¾ãã
// main/kotlin/Main.kt fun main(args: Array<String>) { println(eval(Const(120.0))) // 120.0 println(eval(Sum(Const(10.0), Const(20.0)))) // 30.0 println(eval(NotANumber)) // NaN } fun eval(expr: Expr): Double = when(expr) { is Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) // åèµ·çã«å¼ã³åºãã¦å¤ãåå¾ãã is NotANumber -> Double.NaN // ç¶æ¿ãå¶éããã¦ããããelseãä¸è¦ } // sealedã§å®£è¨ãããExprã¯ã©ã¹ã«ã¢ã¯ã»ã¹ã§ããªããããã³ã³ãã¤ã«ã¨ã©ã¼ã¨ãªã // data class Multiply(val e1: Expr, val e2: Expr) : Expr()
Javaã§ã®Sealed Types
ã¾ããåè¿°ã®Kotlinã§å®è£ ããå 容ãJava 1.8ã§å®è£ ãã¦ã¿ã¾ãã
// main/java/NonSealedTypesSample; public class NonSealedTypesSample { interface Expr{} class Const implements Expr { Double i; Const(Double i){this.i = i; } } class Sum implements Expr { Const a; Const b; Sum(Const a, Const b){this.a = a; this.b = b; } } class NotANumber implements Expr{} }
Kotlinããã®å¾ã«æ¸ãã³ã¼ãã¨ã®æ¯è¼ã®ããã«åã¤ã³ãã¼ã¯ã©ã¹ã¯ã¯ã³ã©ã¤ãã¼ã§å®è£ ãã¦ãã¾ãã
// main/java/Main.java public class Main { public static void main(String[] args) { NonSealedTypesSample nonSealedTypesSample = new NonSealedTypesSample(); System.out.println(eval(nonSealedTypesSample.new Const(120.0))); System.out.println(eval(nonSealedTypesSample.new Sum(nonSealedTypesSample.new Const(10.0), nonSealedTypesSample.new Const(20.0)))); System.out.println(eval(nonSealedTypesSample.new NotANumber())); } private static Double eval(NonSealedTypesSample.Expr expr) { Double result; if (expr instanceof NonSealedTypesSample.Const) { NonSealedTypesSample.Const constant = (NonSealedTypesSample.Const) expr; return constant.i; } else if (expr instanceof NonSealedTypesSample.Sum) { NonSealedTypesSample.Sum sum = (NonSealedTypesSample.Sum) expr; result = sum.a.i + sum.b.i; } else if (expr instanceof NonSealedTypesSample.NotANumber) { result = Double.NaN; } else { result = Double.NaN; } return result; } }
instanceof
ã§æ¯è¼ãã¦ããããå夿ãã¦ã»ã»ã»ã¨ããåé·ãªè¨è¿°ã«ãªã£ã¦ãã¾ãã¾ããã
ãã®ã½ã¼ã¹ã³ã¼ãããä»å¾è¿½å ãããäºå®ã®æ©è½ããJava 1.9以éã«è¿½å ãããæ©è½ãé§ä½¿ãã¦æ¸ãç´ãã¦ã¿ã¾ãã
// main/java/SealedTypesSample; public class SealedTypesSample { sealed interface Expr{} record Const( Double i ) implements Expr { } record Sum( Const a, Const b ) implements Expr { } record NotANumber implements Expr{} }
ã¾ããsealed
ã§å®£è¨ãããã¨ã«ãããå®è£
ã»ç¶æ¿å
ãåä¸ã³ã³ãã¤ã«åä½å
ã®ã¯ã©ã¹ã®ã¿ã«å¶éããã¾ãã
åä¸ã³ã³ãã¤ã«åä½å
ã§ããããã«ç¹å®ã®ã¯ã©ã¹ã«ã®ã¿å®è£
ã»ç¶æ¿ãèªããå ´åã以ä¸ã®ããã«å®è£
ãã¾ãã
sealed interface Expr permits Const, Sum{}
ä¸è¨ã§ã¯Constã¨Sumããå®è£
ã»ç¶æ¿ã§ããªãã¨ãã¦ãããããNotANumberã§å®è£
ã»ç¶æ¿ãããã¨ããã¨ã¨ã©ã¼ã«ãªãã¾ãã
次ã«record
ã§ããããã¯ãã®ã¯ã©ã¹ããã¼ã¿ã®ä¿æãç®çã¨ããåã§ããã¨å®£è¨ãããã®ã§ãï¼JEP 359: Recordsï¼ã
Java 14, Java 15ã§ã¯Previewã¨ãã¦å
¥ããJava 16ã§æ£å¼åããè¦è¾¼ã¿ã§ãã
ããã§ã¯Mainã¯ã©ã¹å´ãåæ§ã«æ¸ãç´ãã¦ã¿ã¾ãã
// main/java/Main.java public class Main { public static void main(String[] args) { SealedTypesSample sealedTypesSample = new SealedTypesSample(); System.out.println(eval(sealedTypesSample.new Const(120.0))); System.out.println(eval(sealedTypesSample.new Sum(sealedTypesSample.new Const(10.0), sealedTypesSample.new Const(20.0)))); System.out.println(eval(sealedTypesSample.new NotANumber())); } private static Double eval(SealedTypesSample.Expr expr) { return switch (e) { case SealedTypesSample.Const(var i) -> i; case SealedTypesSample.Sum(var a, var b) -> eval(a) + eval(b); // åèµ·çã«å¼ã³åºãã¦å¤ãåå¾ãã case SealedTypesSample.NotANumber -> Double.NaN; // ç¶æ¿ãå¶éããã¦ããããdefaultãä¸è¦ } } }
eval
ã¡ã½ããã®å®è£
ã大ãã夿´ããã¦ãã¾ãã
ããã¯Switchæã§ãã¿ã¼ã³ããããè¡ããããã«ããPattern matching for switchã¨ããJEPï¼ã¾ã draftï¼ã¨ãæ¡å¼µswitchï¼switchå¼ï¼ã®å®è£
ã«ããã¨ããã大ããã§ãã
åèï¼Pattern matching for switch
ã¾ããPattern matching for switchã§ã¯å
é¨çã«ãinstance ofãæ¹åããããã«ãã¿ã¼ã³ãããã³ã°æ©è½ã使ããã¦ãã¾ããï¼JEP 305:Pattern Matching for instanceof (Preview)ï¼
ãã®ãã¿ã¼ã³ãããã³ã°æ©è½ã¯instance ofã§æ¯è¼ããã¨ãã«åãä¸è´ãã¦ããå ´åãtrue
ãè¿å´ãã夿°ã¸ã®ä»£å
¥ãè¡ããã®ã«ãªãã¾ãã
if (x instanceof Integer i) { // xã夿°iã«ä»£å ¥ããiãIntegerã¨ãã¦ä½¿ãã }
recodeã§å®£è¨ãããã¯ã©ã¹ã§ã¯ãæ§é ã®åè§£ï¼deconstructible
ï¼ãè¡ããã¨ã§ã(var i) -> i
ã¨ããè¨è¼ã§ã¡ã³ã夿°ã使ããããã«ãªãããã§ããdeconstructibleã«ã¤ãã¦ã¯ãã¾ã JEPã«ãªã£ã¦ãã¾ããããrecodeã®previewã®2次ãã§ã¼ãºã¨ãã¦å®è£
ãããå¯è½æ§ãããã¾ãã
åèï¼[records] Record updates for Preview/2
Javaã¨Kotlinãæ¯è¼ãã¦ã¿ã¦
ç¶æ¿ã®å¯¾è±¡ãå¶éããã¨ããåä½ã®æ©è½ã§è¦ãã¨Sealed Typesã¨Sealed Classã¯åãããã«æãã¾ãã
ããããswitchï¼whenï¼å¨ãã®ç¶æ³ãè¦ãã¨åãããã«å®è£
ããã«ã¯å°ãæéããããããããã¾ããã
ãã ãJEPãè¦ã¦ããã¨è¿ãå°æ¥ï¼Java 16ã17ãããï¼1ã2å¹´å¾ï¼ã«ã¯ãã»ã¨ãã©åããããªè¨è¿°éã§å®è£
ãã§ããããã«ãªãããã«æãã¾ãã
調ã¹ã¦ã¿ã¦
JEPå¨ããä¸éãçºãã¦ãä»å¾ã®Javaãã©ããªããèãããã£ããã«ãªãã¾ããã
ä»åã¯Kotlinã¨ã®æ¯è¼ã«ãªãã¾ããããæ§ã
ãªè¨èªã®å½±é¿ãåãã¦ãªãªã¼ã¹ããã¦ããã®ã§ãC#ãªã©ä»ã®è¨èªã¨ã®æ¯è¼ãªã©ãè¦ã¦è¡ãããã¨æãã¾ãã
P.S.
åãã¦æå¹ã§æ¡ç¨èª¬æä¼ã宿½ãããã¨ã«ãªãã¾ããï¼è¿é£ã«ãä½ã¾ãã®æ¹ã¯ãã²ãç³ãè¾¼ã¿ãã ããï¼ yumenosora.connpass.com
宿çã«è¡ã£ã¦ããç§èå説æä¼ã«ã¤ãã¦ãéå¬ãã¾ãï¼ãèå³ããã話ãèãã¦ã¿ãã人ããå¿åããåã«è©±ãèãããäººãæ¯éãè¶ããã ããï¼
yumenosora.connpass.com
æå¾ã«ãã«ã¸ã¥ã¢ã«é¢è«ã¯éæåä»ä¸ã§ãã®ã§ãæ°ã«ãªãæ¹ã¯ãã²ãç³ãè¾¼ã¿ãã ããã
yumenosora.connpass.com