ロケールによって数値表現が変わるので注意しようってお話です
特にユーザー端末で実行されるアプリでは、様々なロケールでの動作を考慮する必要があります
日本語や英語では小数点に「.」(ピリオド)を使用するため、これ以外の表現が使われることを意識していない人も多いのではないでしょうか?イタリア、ドイツ、フランス、ロシア語などでは「,」(コンマ)が使われるため、変換時に「.」(ピリオド)が使われることを前提にしていると不具合になってしまう場合があります。
ということで、以下を実行してみましょう。
fun main() {
Locale.setDefault(Locale.JAPAN)
println("%.1f".format(1.1))
println(1.1.toString())
println("1.1".toDoubleOrNull())
println("1,1".toDoubleOrNull())
println(DecimalFormat().parse("1,1").toDouble())
println()
Locale.setDefault(Locale.FRANCE)
println("%.1f".format(1.1))
println(1.1.toString())
println("1.1".toDoubleOrNull())
println("1,1".toDoubleOrNull())
println(DecimalFormat().parse("1,1").toDouble())
}
結果
1.1
1.1
1.1
null
11.0
1,1
1.1
1.1
null
1.1
String.format
やDesimalFormat.parse
を使った場合はロケール設定が反映されるため挙動が変わります。
一方Double.toString()
やDouble.parseDouble
はロケール設定に影響されず、「.」(ピリオド)が小数点として使われていますね。
表示するために文字列に変換したり、ユーザー入力の値をパースを行う場合はString.format
やDesimalFormat.parse
を使うのが良いでしょう。
一方、URLなど外部APIアクセスに使用するための文字列や、内部処理のための、文字列⇔数値変換ではDouble.toString()
やDouble.parseDouble
を使用する、String.format
を使う場合はロケールを明示的に指定する必要があります。
ロケールが小数点に影響するとは意識しておらず、この問題になかなか気づけませんでした。
さすがに全言語環境での確認はできませんが、こういう問題もあると言うことを覚えておきましょう。