Kotlin を趣味で触り始めて数日ですが, Java の痒い所が丁寧にサポートされていて感動しています. BigDecimal 演算もその一つです.
業務アプリでは数値演算が必要になる事が多いですが, Double は使えたものではないので BigDecimal 一択です. そしてこの BigDecimal 演算は, 可読性が低いことこの上ありません.
コーディングスタイル比較
基本編
/**
* BigDecimal coding style : (a + b) / 2
*/
fun main(args: Array<String>) {
val a = BigDecimal.ONE
val b = BigDecimal.TEN
// Java style
println(a.add(b).divide(BigDecimal.valueOf(2L), RoundingMode.HALF_EVEN))
// Kotlin basic style
println((a + b) / 2.toBigDecimal())
}
Javaはひどい有様です.
Kotlinは四則演算の演算子を適用できるため, 非常に見やすくなりました. ただ 2.toBigDecimal()
には依然不満が残ります.
応用編
/** custome operator BigDecimal / Long */
operator fun BigDecimal.div(other : Long) : BigDecimal = this / other.toBigDecimal()
/**
* BigDecimal coding style : (a + b) / 2
*/
fun main(args: Array<String>) {
val a = BigDecimal.ONE
val b = BigDecimal.TEN
// Java style
println(a.add(b).divide(BigDecimal.valueOf(2L), RoundingMode.UP))
// Kotlin custom oeprator style
println((a + b) / 2)
}
BigDecimal / Long
の独自演算子を実装することで, 可読性がより上がりました.
仕組みについて
Kotlin の演算子の実現方法
Kotlin において演算子は, 決められたメソッドを呼び出すことと等価になります. Operator overloading において, 各演算子とそれに対応するメソッドが示されています. 四則演算子を抜粋すると以下になります.
Expression | Translated to |
---|---|
a + b |
a.plus(b) |
a - b |
a.minus(b) |
a * b |
a.times(b) |
a / b |
a.div(b) |
a % b |
a.rem(b) , a.mod(b) (deprecated) |
a..b |
a.rangeTo(b) |
plus
などのメソッドを operator fun
で実装することによって, 任意のクラス間の演算子を独自定義することができます.
BigDecimal に対する演算子の実装
kotlin-stdlib に含まれている BigDecimals.kt に演算子の実装が記述されています. サンプルとして除算 "/" の実装を抜粋します. BigDecimal#divide
が利用されており, 更に引数に RoundingMode.HALF_EVEN
が使われていることが確認できます.
/**
* Enables the use of the `/` operator for [BigDecimal] instances.
*
* The scale of the result is the same as the scale of `this` (divident), and for rounding the [RoundingMode.HALF_EVEN]
* rounding mode is used.
*/
@kotlin.internal.InlineOnly
public inline operator fun BigDecimal.div(other: BigDecimal): BigDecimal = this.divide(other, RoundingMode.HALF_EVEN)