1. 概要

この記事では、DecimalFormatクラスとその実際の使用法について説明します。

これはNumberFormatのサブクラスであり、事前定義されたパターンを使用して10進数のString表現をフォーマットできます。

文字列を数値に解析するために、逆に使用することもできます。

2. それはどのように機能しますか?

数値をフォーマットするには、パターンを定義する必要があります。これは、テキストと混合される可能性のある特殊文字のシーケンスです。

11の特殊パターン文字がありますが、最も重要なものは次のとおりです。

  • 0 –指定されている場合は数字を出力し、指定されていない場合は0を出力します。
  • #–提供されている場合は数字を印刷し、それ以外の場合は何も印刷しません
  • 。 –小数点を置く場所を示します
  • 、–グループ化区切り文字を配置する場所を示します

パターンが数値に適用されると、そのフォーマットルールが実行され、特定の Locale を除き、JVMのLocaleDecimalFormatSymbolに従って結果が出力されます。が指定されています。

次の例の出力は、英語のLocaleで実行されているJVMからのものです。

3. 基本的なフォーマット

次のパターンで同じ数値をフォーマットしたときに生成される出力を見てみましょう。

3.1. 単純な小数

double d = 1234567.89;    
assertThat(
  new DecimalFormat("#.##").format(d)).isEqualTo("1234567.89");
assertThat(
  new DecimalFormat("0.00").format(d)).isEqualTo("1234567.89");

ご覧のとおり、パターンが数値よりも小さいかどうかに関係なく、整数部分が破棄されることはありません。

assertThat(new DecimalFormat("#########.###").format(d))
  .isEqualTo("1234567.89");
assertThat(new DecimalFormat("000000000.000").format(d))
  .isEqualTo("001234567.890");

代わりにパターンが数値よりも大きい場合、整数と小数の両方でゼロが追加され、ハッシュは削除されます。

3.2. 丸め

パターンの小数部分に入力数値の精度全体を含めることができない場合は、丸められます。

ここでは、.89部分が.90に丸められ、0が削除されています。

assertThat(new DecimalFormat("#.#").format(d))
  .isEqualTo("1234567.9");

ここでは、.89の部分が1.00に丸められ、次に.00が削除され、1が7に合計されています。

assertThat(new DecimalFormat("#").format(d))
  .isEqualTo("1234568");

デフォルトの丸めモードはHALF_EVEN、ですが、setRoundingModeメソッドを使用してカスタマイズできます。

3.3. グループ化

グループ化区切り文字は、自動的に繰り返されるサブパターンを指定するために使用されます。

assertThat(new DecimalFormat("#,###.#").format(d))
  .isEqualTo("1,234,567.9");
assertThat(new DecimalFormat("#,###").format(d))
  .isEqualTo("1,234,568");

3.4. 複数のグループ化パターン

一部の国では、番号付けシステムにさまざまな数のグループ化パターンがあります。

インドの命数法は、#、##、###。##の形式を使用します。この形式では、最初のグループ化区切り文字のみが3つの数値を保持し、他のすべては2つの数値を保持します。

これは、 DecimalFormat クラスを使用して実現することはできません。このクラスは、左から右に検出された最新のパターンのみを保持し、以前のグループ化パターンを無視して整数に適用します。

パターン#、##、##、##、###を使用しようとすると、#######、###に再グループ化され、#、###、#に再配布されます。 ##、###。

複数のグループ化パターンマッチングを実現するには、独自の String 操作コードを作成するか、Icu4JのDecimalFormatを試す必要があります。

3.5. 文字列リテラルの混合

パターン内でStringリテラルを混在させることができます。

assertThat(new DecimalFormat("The # number")
  .format(d))
  .isEqualTo("The 1234568 number");

エスケープすることにより、Stringリテラルとして特殊文字を使用することもできます。

assertThat(new DecimalFormat("The '#' # number")
  .format(d))
  .isEqualTo("The # 1234568 number");

4. ローカライズされたフォーマット

多くのは英語の記号を使用せず、小数点記号としてコンマを使用し、グループ化区切り文字としてドットを使用します。

たとえば、イタリア語の Locale を使用してJVMで#、###。##パターンを実行すると、1.234.567,89が出力されます。

これは便利なi18n機能である場合もありますが、特定のJVMに依存しない形式を適用したい場合もあります。

これを行う方法は次のとおりです。

assertThat(new DecimalFormat("#,###.##", 
  new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
  .isEqualTo("1,234,567.89");
assertThat(new DecimalFormat("#,###.##", 
  new DecimalFormatSymbols(Locale.ITALIAN)).format(d))
  .isEqualTo("1.234.567,89");

関心のあるLocaleDecimalFormatSymbolsコンストラクターの対象外である場合は、getInstanceメソッドで指定できます。

Locale customLocale = new Locale("it", "IT");
assertThat(new DecimalFormat(
  "#,###.##", 
   DecimalFormatSymbols.getInstance(customLocale)).format(d))
  .isEqualTo("1.234.567,89");

5. 科学的記数法

科学的記数法は、仮数と10の指数の積を表します。 数値1234567.89は、12.3456789 * 10 ^ 5として表すこともできます(ドットは5桁シフトされます)。

5.1. E-表記

10の指数を表すEパターン文字を使用して、科学的記数法で数値を表すことができます。

assertThat(new DecimalFormat("00.#######E0").format(d))
  .isEqualTo("12.3456789E5");
assertThat(new DecimalFormat("000.000000E0").format(d))
  .isEqualTo("123.456789E4");

指数の後の文字数が関係していることに注意する必要があります。したがって、10 ^ 12を表現する必要がある場合は、E0ではなくE00が必要です。

5.2. 工学的記数法

工学的記数法と呼ばれる特定の形式の科学的記数法を使用するのが一般的です。これは、たとえばキロ(10 ^ 3)、メガ(10 ^ 6)、ギガ(10 ^ 6)などの測定単位を使用する場合に、3の倍数として表現されるように結果を調整します。 10 ^ 9)など。

この種の表記を適用するには、整数の最大桁数(#で表され、小数点の左側にある文字)を最小数(0で表される文字)よりも大きく、より大きくなるように調整します。 1.1。

これにより、指数は最大数の倍数になります。したがって、このユースケースでは、最大数を3にする必要があります。

assertThat(new DecimalFormat("##0.######E0")
  .format(d)).isEqualTo("1.23456789E6");		
assertThat(new DecimalFormat("###.000000E0")
  .format(d)).isEqualTo("1.23456789E6");

6. 構文解析

parseメソッドを使用してStringNumberに解析する方法を見てみましょう。

assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH))
  .parse("1234567.89"))
  .isEqualTo(1234567.89);
assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ITALIAN))
  .parse("1.234.567,89"))
  .isEqualTo(1234567.89);

戻り値は小数点の存在によって推測されないため、返された数値の .doubleValue() .longValue()などのメソッドを使用できます。 出力に特定のプリミティブを適用するオブジェクト。

次のようにBigDecimalを取得することもできます。

NumberFormat nf = new DecimalFormat(
  "", 
  new DecimalFormatSymbols(Locale.ENGLISH));
((DecimalFormat) nf).setParseBigDecimal(true);
 
assertThat(nf.parse("1234567.89"))
  .isEqualTo(BigDecimal.valueOf(1234567.89));

7. スレッドセーフ

DecimalFormatはスレッドセーフではないので、スレッド間で同じインスタンスを共有する場合は特に注意が必要です。

8. 結論

DecimalFormat クラスの主な使用法と、その長所と短所を見てきました。

いつものように、完全なソースコードはGithub利用できます。