ïŒã¿ã¬ã³ãã°äŒæ¥ã®ãªãã£ã¹ã§éå¬ããããã®ãããã¯ã«é¢ããäŒè°ã®åçãMaxilektã®ã¯ãŒãã³ã°ã°ã«ãŒãïŒJavaïŒã®ãªãŒããŒã§ããAlexey Shafranovã話ããïŒ
ååãšããŠã©ã®ããã«ãšã©ãŒãåŠçã§ããŸããïŒ
ç§ã¯ããã€ãã®æ¹æ³ãèŠã€ããŸããïŒ
- ãšã©ãŒããããšããäºå®ãžã®ãã€ã³ã¿ãšããŠäœããã®æ»ãå€ã䜿çšã§ããŸãã
- åãç®çã§ã€ã³ãžã±ãŒã¿ãŒãã©ã¡ãŒã¿ãŒã䜿çšã§ããŸãã ã
- ã°ããŒãã«å€æ°ãå ¥åããŠãã ãã
- äŸå€ãåŠçãã
- å¥çŽã®è¿œå ïŒDbCïŒ ã
åãªãã·ã§ã³ã«ã€ããŠè©³ãã説æããŸãã
æ»ãå€
ãšã©ãŒãçºçããå Žåãç¹å®ã®ãããžãã¯ãå€ãè¿ãããŸãã ã¹ã¯ãªããèšèªã䜿çšããããšãããå Žåã¯ãããããåæ§ã®æ§æäœãèŠãã§ãããã
äŸ1ïŒ
function sqrt(x) { if(x < 0) return -1; else return âx; }
äŸ2ïŒ
function getUser(id) { result = db.getUserById(id) if (result) return result as User else return âCan't find user â + id }
ææšãã©ã¡ãŒã¿ãŒ
é¢æ°ã«æž¡ãããç¹å®ã®ãã©ã¡ãŒã¿ãŒã䜿çšãããŸãã ãã©ã¡ãŒã¿ã«ãã£ãŠå€ãè¿ããåŸãé¢æ°å ã§ãšã©ãŒãçºçãããã©ããã確èªã§ããŸãã
äŸïŒ
function divide(x,y,out Success) { if (y == 0) Success = false else Success = true return x/y } divide(10, 11, Success) id (!Success) //handle error
ã°ããŒãã«å€æ°
ã°ããŒãã«å€æ°ã¯ã»ãŒåãããã«æ©èœããŸãã
äŸïŒ
global Success = true function divide(x,y) { if (y == 0) Success = false else return x/y } divide(10, 11, Success) id (!Success) //handle error
äŸå€
ç§ãã¡ã¯çãäŸå€ã«æ £ããŠããŸãã ã»ãšãã©ã©ãã§ã䜿çšãããŸãã
äŸïŒ
function divide(x,y) { if (y == 0) throw Exception() else return x/y } try{ divide(10, 0)} catch (e) {//handle exception}
å¥çŽïŒDbCïŒ
ççŽã«èšã£ãŠãç§ã¯ãã®ã¢ãããŒããå®éã«èŠãããšããããŸããã é·ãã°ãŒã°ã«æ€çŽ¢ã§ãKotlin 1.3ã«ã¯å®éã«å¥çŽã䜿çšã§ããã©ã€ãã©ãªãããããšãããããŸããã ã€ãŸã é¢æ°ã«æž¡ãããå€æ°ã®æ¡ä»¶ãæ»ãå€ã®æ¡ä»¶ãåŒã³åºãåæ°ãåŒã³åºãå ãªã©ãèšå®ã§ããŸãã ãããŠããã¹ãŠã®æ¡ä»¶ãæºããããŠããã°ãæ©èœã¯æ£ããæ©èœãããšèããããŸãã
äŸïŒ
function sqrt (x) pre-condition (x >= 0) post-condition (return >= 0) begin calculate sqrt from x end
æ£çŽãªãšããããã®ã©ã€ãã©ãªã«ã¯ã²ã©ãæ§æããããŸãã ãããããããç§ããã®ãããªããšãã©ã€ãã§èŠãããšããªãçç±ã§ãã
Javaã®äŸå€
Javaã«ç§»ããæåããJavaãã©ã®ããã«æ©èœããããèŠãŠã¿ãŸãããã
èšèªãèšèšãããšãã«ã2çš®é¡ã®äŸå€ãçºçããŸããã
- ãã§ãã¯æžã¿-ãã§ãã¯æžã¿ã
- æªãã§ãã¯-æªãã§ãã¯ã
ãã§ãã¯å¯Ÿè±¡ã®äŸå€ã¯äœã§ããïŒ çè«çã«ã¯ã人ã ããšã©ãŒããã§ãã¯ããªããã°ãªããªãããã«å¿ èŠã§ãã ã€ãŸã ç¹å®ã®ãã§ãã¯æžã¿äŸå€ãå¯èœãªå Žåã¯ãåŸã§ãã§ãã¯ããå¿ èŠããããŸãã çè«çã«ã¯ããã®ã¢ãããŒãã«ãããæªåŠçã®ãšã©ãŒããªããªããã³ãŒãã®å質ãåäžããã¯ãã§ãã ããããå®éã«ã¯ããã§ã¯ãããŸããã å°ãªããšãäžåºŠã¯èª°ãã空ã®ãã£ãããããã¯ãèŠããšæããŸãã
ãªããããæªãã®ã§ããããïŒ
ããã¯ãKotlinããã¥ã¡ã³ãããçŽæ¥ã®å€å žçãªäŸã§ã-StringBuilderã«å®è£ ãããJDKããã®ã€ã³ã¿ãŒãã§ã€ã¹ïŒ
Appendable append(CharSequence csq) throws IOException; try { log.append(message) } catch (IOException e) { //Must be safe }
éçºè ã«ãããšãtry-catchã§ã©ãããããéåžžã«å€ãã®ã³ãŒãã«åºäŒã£ãã¯ãã§ããcatchã¯ç©ºã®ãããã¯ã§ãã å€ãã®å Žåããã§ãã¯äŸå€ã®åŠçã¯æ¬¡ã®æ¹æ³ã§å®è£ ãããŸããåã«RuntimeExceptionãã¹ããŒããäžèšã®ã©ããã§ãã£ããããŸãïŒãŸãã¯ãã£ããããŸãã...ïŒã
try { // do something } catch (IOException e) { throw new RuntimeException(e); // - ...
ã³ããªã³ã§ã§ããããš
äŸå€ã«é¢ããŠãKotlinã³ã³ãã€ã©ãŒã¯æ¬¡ã®ç¹ã§ç°ãªããŸãã
1.ãã§ãã¯æžã¿äŸå€ãšæªãã§ãã¯äŸå€ãåºå¥ããŸããã ãã¹ãŠã®äŸå€ã¯ãã§ãã¯ãããŠããªãã ãã§ããããããããã£ããããŠåŠçãããã©ããã¯èªåã§æ±ºå®ããŸãã
2. Tryã¯åŒãšããŠäœ¿çšã§ããŸã-tryãããã¯ãå®è¡ããŠãããããæåŸã®è¡ãè¿ãããcatchãããã¯ããæåŸã®è¡ãè¿ãããšãã§ããŸãã
val value = try {Integer.parseInt(âlolâ)} catch(e: NumberFormanException) { 4 } //
3.ãŸããããã€ãã®ãªããžã§ã¯ããåç §ãããšãã«åæ§ã®æ§é ã䜿çšã§ããŸãã
val s = obj.money ?: throw IllegalArgumentException(â , â)
Javaã®äºææ§
Kotlinã³ãŒãã¯Javaã§äœ¿çšã§ãããã®éãå¯èœã§ãã äŸå€ãåŠçããæ¹æ³ã¯ïŒ
- Kotlinã®Javaããã®ãã§ãã¯æžã¿äŸå€ã¯ããã§ãã¯ã宣èšãã§ããŸããïŒKotlinã«ã¯ãã§ãã¯æžã¿äŸå€ããªãããïŒã
- Kotlinã§çºçããå¯èœæ§ã®ãããã§ãã¯æžã¿äŸå€ïŒããšãã°ãå ã JavaããçºçããäŸå€ïŒã¯ãJavaã§ãã§ãã¯ããå¿ èŠã¯ãããŸããã
- ãã§ãã¯ããå¿ èŠãããå Žåã¯ãã¡ãœããã®@Throwsã¢ãããŒã·ã§ã³ã䜿çšããŠäŸå€ãæ€èšŒå¯èœã«ããããšãã§ããŸãïŒãã®ã¡ãœãããã¹ããŒã§ããäŸå€ã瀺ãå¿ èŠããããŸãïŒã äžèšã®æ³šéã¯ãJavaäºææ§ã®ã¿ãç®çãšããŠããŸãã ããããå®éã«ã¯ãå€ãã®äººããã®ã¡ãœããã䜿çšããŠãååãšããŠãããçš®ã®äŸå€ãã¹ããŒã§ããããšã宣èšããŠããŸãã
try-catchãããã¯ã®ä»£æ¿
try-catchãããã¯ã«ã¯é倧ãªæ¬ ç¹ããããŸãã 衚瀺ããããšãããžãã¹ããžãã¯ã®äžéšããã£ããå ã«è»¢éãããããã¯äžèšã®å€ãã®ã¡ãœããã®ããããã§çºçããå¯èœæ§ããããŸãã ããžãã¹ããžãã¯ããããã¯ãŸãã¯ã³ãŒã«ãã§ãŒã³å šäœã«åæ£ããŠããå Žåãã¢ããªã±ãŒã·ã§ã³ã®åäœãç解ããã®ã¯ããå°é£ã§ãã ãŸããå¯èªæ§ãããã¯èªäœã¯ã³ãŒããè¿œå ããŸããã
try { HttpService.SendNotification(endpointUrl); MarkNotificationAsSent(); } catch (e: UnableToConnectToServerException) { MarkNotificationAsNotSent(); }
代æ¿æ段ã¯äœã§ããïŒ
1ã€ã®ãªãã·ã§ã³ã¯ãäŸå€åŠçãžã®æ©èœçãªã¢ãããŒããæäŸããŸãã åæ§ã®å®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
val result: Try<Result> = Try{HttpService.SendNotification(endpointUrl)} when(result) { is Success -> MarkNotificationAsSent() is Failure -> MarkNotificationAsNotSent() }
Tryã¢ããã䜿çšããããšãã§ããŸãã æ¬è³ªçã«ãããã¯äœããã®å€ãæ ŒçŽããã³ã³ããã§ãã flatMapã¯ããã®ã³ã³ãããæäœããæ¹æ³ã§ãããã®ã³ã³ããã¯ãçŸåšã®å€ãšäžç·ã«é¢æ°ãåãåããåã³ã¢ãããè¿ãããšãã§ããŸãã
ãã®å ŽåãåŒã³åºãã¯Tryã¢ããã«ã©ãããããŸãïŒTryãè¿ããŸãïŒã å¿ èŠãªå Žæã§1ãæã§åŠçã§ããŸãã åºåã«å€ãããå Žåã次ã®ã¢ã¯ã·ã§ã³ãå®è¡ããŸããäŸå€ãã¹ããŒãããå Žåããã§ãŒã³ã®æåŸã§åŠçããŸãã
æ©èœçãªäŸå€åŠç
Tryã¯ã©ãã§å ¥æã§ããŸããïŒ
ãŸããTryã¯ã©ã¹ãšBothã¯ã©ã¹ã®ã³ãã¥ããã£å®è£ ã¯ããªããããŸãã ãããã䜿çšããããšããèªåã§å®è£ ãäœæããããšãã§ããŸãã ãæŠéããããžã§ã¯ãã®1ã€ã§ãTryã®èªäœã®å®è£ ã䜿çšããŸããã1ã€ã®ã¯ã©ã¹ã§ç®¡çããçŽ æŽãããä»äºãããŸããã
第äºã«ãKotlinã«å€ãã®æ©èœãè¿œå ããArrowã©ã€ãã©ãªããããŸãã åœç¶ãTryãšBothããããŸãã
ããã«å ããŠãçµæã¯ã©ã¹ã¯Kotlin 1.3ã«ç»å ŽããŸãããããã«ã€ããŠã¯åŸã§è©³ãã説æããŸãã
äŸãšããŠArrowã©ã€ãã©ãªãŒã䜿çšããŠã¿ãŠãã ãã
Arrowã©ã€ãã©ãªãŒã¯ãTryã¯ã©ã¹ãæäŸããŸãã å®éã«ã¯ãæåãŸãã¯å€±æã®2ã€ã®ç¶æ ã«ãªããŸãã
- åºéãæåããŠããåœç€Ÿã®äŸ¡å€ã¯ç¶æãããŸããã
- 倱æã¯ãã³ãŒããããã¯ã®å®è¡äžã«çºçããäŸå€ãä¿åããŸãã
åŒã³åºãã¯æ¬¡ã®ãšããã§ãã åœç¶ãéåžžã®try-catchã§ã©ãããããŸãããããã¯ã³ãŒãå ã®ã©ããã§çºçããŸãã
sealed class Try<out A> { data class Success<out A>(val value: A) : Try<A>() data class Failure(val e: Throwable) : Try<Nothing>() companion object { operator fun <A> invoke(body: () -> A): Try<A> { return try { Success(body()) } catch (e: Exception) { Failure(e) } } }
åãã¯ã©ã¹ã§flatMapã¡ãœãããå®è£ ããå¿ èŠããããŸããããã«ãããé¢æ°ãæž¡ããŠtryã¢ãããè¿ãããšãã§ããŸãã
inline fun <B> map(f: (A) -> B): Try<B> = flatMap { Success(f(it)) } inline fun <B> flatMap(f: (A) -> TryOf<B>): Try<B> = when (this) { is Failure -> this is Success -> f(value) }
ããã¯äœã®ããã§ããïŒ çµæãè€æ°ããå Žåã«åçµæã®ãšã©ãŒãåŠçããªãããã«ããããã ããšãã°ãããŸããŸãªãµãŒãã¹ããããã€ãã®å€ãååŸããããããçµã¿åãããããšããŸãã å®éã2ã€ã®ç¶æ³ãçºçããå¯èœæ§ããããŸããããããæ£åžžã«åä¿¡ããŠçµåããããäœããèœã¡ãŸããã ãããã£ãŠã次ã®ããšãã§ããŸãã
val result1: Try<Int> = Try { 11 } val result2: Try<Int> = Try { 4 } val sum = result1.flatMap { one -> result2.map { two -> one + two } } println(sum) //Success(value=15)
äž¡æ¹ã®åŒã³åºããæåããå€ãååŸããå Žåãé¢æ°ãå®è¡ããŸãã æåããªãã£ãå ŽåãFailureã¯äŸå€ãè¿ããŸãã
äœããèœã¡ãå Žåã次ã®ããã«ãªããŸãã
val result1: Try<Int> = Try { 11 } val result2: Try<Int> = Try { throw RuntimeException(âOh no!â) } val sum = result1.flatMap { one -> result2.map { two -> one + two } } println(sum) //Failure(exception=java.lang.RuntimeException: Oh no!
åãé¢æ°ã䜿çšããŸããããåºåã¯RuntimeExceptionããã®å€±æã§ãã
ãŸããArrowã©ã€ãã©ãªã䜿çšãããšãå®éã«ã¯æ§æç³ãç¹ã«ãã€ã³ãã£ã³ã°ã®æ§æã䜿çšã§ããŸãã ã·ãªã¢ã«flatMapã䜿çšããŠãã¹ãŠåããã®ãæžãæããããšãã§ããŸããããã€ã³ãã£ã³ã°ã䜿çšããããšã§èªã¿åãå¯èœã«ããããšãã§ããŸãã
val result1: Try<Int> = Try { 11 } val result2: Try<Int> = Try { 4 } val result3: Try<Int> = Try { throw RuntimeException(âOh no, again!â) } val sum = binding { val (one) = result1 val (two) = result2 val (three) = result3 one + two + three } println(sum) //Failure(exception=java.lang.RuntimeException: Oh no, again!
çµæã®1ã€ãèœã¡ãå Žåãåºåã«ãšã©ãŒã衚瀺ãããŸãã
åæ§ã®ã¢ãããéåæåŒã³åºãã«äœ¿çšã§ããŸãã ããšãã°ãéåæã«å®è¡ããã2ã€ã®é¢æ°ã次ã«ç€ºããŸãã ã¹ããŒã¿ã¹ãåå¥ã«ç¢ºèªããã«ãåãæ¹æ³ã§çµæãçµåããŸãã
fun funA(): Try<Int> { return Try { 1 } } fun funB(): Try<Int> { Thread.sleep(3000L) return Try { 2 } } val a = GlobalScope.async { funA() } val b = GlobalScope.async { funB() } val sum = runBlocking { a.await().flatMap { one -> b.await().map {two -> one + two } } }
ãããŠãããã«ãã£ãšãæŠéãã®äŸããããŸãã ãµãŒããŒãžã®ãªã¯ãšã¹ããããããããåŠçããããããããã£ãååŸããããããã§ã«ããŒã¿ãè¿ããŠããã¯ã©ã¹ã«ãããããããšããŸãã
fun makeRequest(request: Request): Try<List<ResponseData>> = Try { httpClient.newCall(request).execute() } .map { it.body() } .flatMap { Try { ObjectMapper().readValue(it, ParsedResponse::class.java) } } .map { it.data } fun main(args : Array<String>) { val response = makeRequest(RequestBody(args)) when(response) { is Try.Success -> response.data.toString() is Try.Failure -> response.exception.message } }
Try-catchã䜿çšãããšããã®ãããã¯ã®èªã¿ããããå€§å¹ ã«äœäžããŸãã ãã®å Žåãåºåã§response.dataãååŸããçµæã«å¿ããŠåŠçã§ããŸãã
Kotlin 1.3ã®çµæ
Kotlin 1.3ã¯Resultã¯ã©ã¹ãå°å ¥ããŸããã å®éãTryã«äŒŒãŠããŸãããããã€ãã®å¶éããããŸãã å ã ã¯ãããŸããŸãªéåææäœã«äœ¿çšããããšãç®çãšããŠããŸãã
val result: Result<VeryImportantData> = Result.runCatching { makeRequest() } .mapCatching { parseResponse(it) } .mapCatching { prepareData(it) } result.fold{ { data -> println(âWe have $dataâ) }, exception -> println(âThere is no any data, but it's your exception $exceptionâ) } )
ééã£ãŠããªãå Žåããã®ã¯ã©ã¹ã¯çŸåšå®éšçã§ãã èšèªéçºè ã¯ãã·ã°ããã£ãåäœãå€æŽããããå®å šã«åé€ãããã§ãããããçŸæç¹ã§ã¯ã¡ãœãããŸãã¯å€æ°ããã®æ»ãå€ãšããŠäœ¿çšããããšã¯çŠæ¢ãããŠããŸãã ãã ããããŒã«ã«ïŒãã©ã€ããŒãïŒå€æ°ãšããŠäœ¿çšã§ããŸãã ã€ãŸã å®éãäŸããè©ŠããŠã¿ãããšãã§ããŸãã
çµè«
ç§ãèªåã®ããã«ããçµè«ïŒ
- Kotlinã®æ©èœãšã©ãŒåŠçã¯ã·ã³ãã«ã§äŸ¿å©ã§ãã
- å€å žçãªã¹ã¿ã€ã«ã®try-catchãä»ããŠããããåŠçããããšã誰ãæ°ã«ããŸããïŒãããšããã®äž¡æ¹ã«çåœæš©ããããŸã;ãããšããã®äž¡æ¹ã䟿å©ã§ãïŒ
- ãã§ãã¯ãããäŸå€ããªãããšã¯ããšã©ãŒãåŠçã§ããªãããšãæå³ããŸããã
- çç£ã«é¢ãããã£ãããããªãäŸå€ã¯ãæ²ããçµæããããããŸãã
èšäºã®èè ïŒAlexey Shafranovãã¯ãŒãã³ã°ã°ã«ãŒãïŒJavaïŒã®ãªãŒããŒãMaxilect
PS Runetã®ããã€ãã®ãµã€ãã§èšäºãå ¬éããŠããŸãã VK ã FBããŸãã¯é»å ±ãã£ãã«ã®ããŒãžã賌èªããŠããã¹ãŠã®åºçç©ããã®ä»ã®Maxilectãã¥ãŒã¹ã«ã€ããŠåŠã³ãŸãã