Number Formatting in Java – Java中的数字格式化

最后修改: 2020年 6月 25日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll learn about the different approaches to number formatting in Java, and how to implement them.

在本教程中,我们将了解Java中数字格式化的不同方法,以及如何实现它们。

2. Basic Number Formatting With String#format

2.用String#format进行基本数字格式化

The String#format method is very useful for formatting numbers. The method takes two arguments. The first argument describes the pattern of how many decimals places we want to see, and the second argument is the given value:

String#format方法对于格式化数字非常有用。该方法需要两个参数。第一个参数描述了我们想看到的小数位数的模式,第二个参数是给定值。

double value = 4.2352989244d;
assertThat(String.format("%.2f", value)).isEqualTo("4.24");
assertThat(String.format("%.3f", value)).isEqualTo("4.235");

3. Decimal Formatting by Rounding

3.通过四舍五入实现小数点格式化

In Java, we have two primitive types that represent decimal numbers, float and decimal:

在Java中,我们有两种表示小数的原始类型,floatdecimal

double myDouble = 7.8723d;
float myFloat = 7.8723f;

The number of decimal places can be different depending on the operations being performed. In most cases, we’re only interested in the first couple of decimal places. Let’s take a look at some ways to format a decimal by rounding.

小数点后的位数可以是不同的,这取决于所进行的操作。在大多数情况下,我们只对小数的前几位感兴趣。让我们来看看通过四舍五入对小数进行格式化的一些方法。

3.1. Using BigDecimal for Number Formatting

3.1.使用BigDecimal进行数字格式化

The BigDecimal class provides methods to round to a specified number of decimal places. Let’s create a helper method that will return a double, rounded to a desired number of places:

BigDecimal类提供了四舍五入到指定小数位数的方法。让我们创建一个辅助方法,它将返回一个四舍五入到所需位数的双数。

public static double withBigDecimal(double value, int places) {
    BigDecimal bigDecimal = new BigDecimal(value);
    bigDecimal = bigDecimal.setScale(places, RoundingMode.HALF_UP);
    return bigDecimal.doubleValue();
}

We’ll start with a new instance of BigDecimal with our original decimal value. Then, by setting the scale, we’ll provide the number of decimal places we want, and how we want to round our number. Using this method allows us to easily format a double value:

我们将从一个新的BigDecimal的实例开始,其中包含我们的原始小数值。然后,通过设置比例,我们将提供我们想要的小数位数,以及我们想要的四舍五入方式。使用这种方法,我们可以轻松地格式化一个double值。

double D = 4.2352989244d;
assertThat(withBigDecimal(D, 2)).isEqualTo(4.24);
assertThat(withBigDecimal(D, 3)).isEqualTo(4.235);

3.2. Using Math#round

3.2.使用Math#round

We can also take advantage of the static methods in the Math class to round a double value to a specified decimal place. In this case, we can adjust the number of decimal places by multiplying and later dividing by 10^n. Let’s check our helper method:

我们还可以利用Math中的静态方法,将double值四舍五入到指定的小数位。在这种情况下,我们可以通过乘以10^n来调整小数点后的数字。让我们检查一下我们的辅助方法。

public static double withMathRound(double value, int places) {
    double scale = Math.pow(10, places);
    return Math.round(value * scale) / scale;
}
assertThat(withMathRound(D, 2)).isEqualTo(4.24);
assertThat(withMathRound(D, 3)).isEqualTo(4.235);

However, this option is only recommended in particular cases, as sometimes the output might be rounded differently than expected before it’s printed.

然而,只有在特殊情况下才推荐使用这个选项,因为有时在打印之前,输出的圆角可能与预期的不同。

This is because Math#round is truncating the value. Let’s see how this can happen:

这是因为Math#round正在截断这个值。让我们看看这种情况是如何发生的。

System.out.println(withMathRound(1000.0d, 17));
// Gives: 92.23372036854776 !!
System.out.println(withMathRound(260.775d, 2));
// Gives: 260.77 instead of expected 260.78

So please note that this method is only listed for learning purposes.

所以请注意,这个方法只是为了学习而列出。

4. Formatting Different Types of Numbers

4.格式化不同类型的数字

In some particular cases, we may want to format a number for a specific type, like currency, large integer, or percentage.

在一些特殊情况下,我们可能想把一个数字格式化为一个特定的类型,如货币、大整数或百分比。

4.1. Formatting Large Integers With Commas

4.1.用逗号对大整数进行格式化

Whenever we have a large integer in our application, we may want to display it with commas by using DecimalFormat with a predefined pattern:

每当我们的应用程序中有一个大的整数时,我们可能想通过使用带有预定义模式的DecimalFormat来用逗号显示它。

public static String withLargeIntegers(double value) {
    DecimalFormat df = new DecimalFormat("###,###,###");
    return df.format(value);
}

int value = 123456789;
assertThat(withLargeIntegers(value)).isEqualTo("123,456,789");

4.2. Padding a Number

4.2.填充一个数字

In some cases, we may want to pad a number with zeros for a specified length. Here, we can use the String#format method, as described earlier:

在某些情况下,我们可能想用零来填充一个指定长度的数字。这里,我们可以使用String#format方法,如前所述。

public static String byPaddingZeros(int value, int paddingLength) {
    return String.format("%0" + paddingLength + "d", value);
}

int value = 1;
assertThat(byPaddingOutZeros(value, 3)).isEqualTo("001");

4.3. Formatting Numbers With Two Zeros After the Decimal

4.3.小数点后有两个零的数字的格式化

To be able to print any given number with two zeros after the decimal point, we’ll again use the DecimalFormat class with a predefined pattern:

为了能够打印小数点后有两个零的任何给定数字,我们将再次使用带有预定义模式的DecimalFormat类。

public static double withTwoDecimalPlaces(double value) {
    DecimalFormat df = new DecimalFormat("#.00");
    return new Double(df.format(value));
}

int value = 12; 
assertThat(withTwoDecimalPlaces(value)).isEqualTo(12.00);

In this case, we created a new format with a pattern specifying two zeros after the decimal point.

在这种情况下,我们创建了一个新的格式,其模式是在小数点后指定两个零

4.4. Formatting and Percentages

4.4.格式化和百分比

From time to time we might need to display percentages.

有时我们可能需要显示百分比。

In this case, we can use the NumberFormat#getPercentInstance method. This method allows us to provide a Locale to print the value in a format that’s correct for the country we specified:

在这种情况下,我们可以使用NumberFormat#getPercentInstance方法。这个方法允许我们提供一个Locale,以正确的格式来打印我们指定的国家的值。

public static String forPercentages(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getPercentInstance(locale);
    return nf.format(value);
}

double value = 25f / 100f;
assertThat(forPercentages(value, new Locale("en", "US"))).isEqualTo("25%");

4.5. Currency Number Formatting

4.5.货币数字格式化

A common way to store currencies in our application is by using the BigDecimal. If we want to display them to the user, we can use the NumberFormat class:

在我们的应用程序中存储货币的一种常见方式是使用BigDecimal。如果我们想向用户显示它们,我们可以使用NumberFormat类。

public static String currencyWithChosenLocalisation(double value, Locale locale) {
    NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
    return nf.format(value);
}

We get the currency instance for a given Locale and then simply call the format method with the value. The result is the number displayed as a currency for the specified country:

我们获取给定Locale的货币实例,然后简单地用该值调用format方法。其结果是将数字显示为指定国家的货币。

double value = 23_500;
assertThat(currencyWithChosenLocalisation(value, new Locale("en", "US"))).isEqualTo("$23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("zh", "CN"))).isEqualTo("¥23,500.00");
assertThat(currencyWithChosenLocalisation(value, new Locale("pl", "PL"))).isEqualTo("23 500 zł");

5. Advanced Formatting Use-Cases

5.高级格式化应用案例

DecimalFormat is one of the most popular ways to format a decimal number in Java. Similar to previous examples, we’ll write a helper method:

DecimalFormat是在Java中格式化小数的最常用方法之一。与之前的例子类似,我们将编写一个辅助方法。

public static double withDecimalFormatLocal(double value) {
    DecimalFormat df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.getDefault());
    return new Double(df.format(value));
}

Our type of formatting will get the default setting for a given localization.

我们的格式化类型将获得特定本地化的默认设置。

The decimal formatting is handled differently in different countries using their numeric systems. This includes the grouping character (comma in the US, but space or dot in other locales), the grouping size (three in the US and most locales, but different in India), or the decimal character (dot in the US, but a comma in other locales).

不同国家使用其数字系统,对小数的格式化处理是不同的。这包括分组字符(在美国是逗号,但在其他地区是空格或点),分组大小(在美国和大多数地区是三,但在印度是不同的),或小数点字符(在美国是点,但在其他地区是逗号)。

double D = 4.2352989244d;
assertThat(withDecimalFormatLocal(D)).isEqualTo(4.235);

We can also extend this functionality to provide some specific patterns:

我们还可以扩展这个功能,提供一些特定的模式。

public static double withDecimalFormatPattern(double value, int places) {
    DecimalFormat df2 = new DecimalFormat("#,###,###,##0.00");
    DecimalFormat df3 = new DecimalFormat("#,###,###,##0.000");
    if (places == 2)
        return new Double(df2.format(value));
    else if (places == 3)
        return new Double(df3.format(value));
    else
        throw new IllegalArgumentException();
}

assertThat(withDecimalFormatPattern(D, 2)).isEqualTo(4.24); 
assertThat(withDecimalFormatPattern(D, 3)).isEqualTo(4.235);

Here we allow our user to configure DecimalFormat by chosen pattern based on the number of spaces.

在这里,我们允许用户根据空格的数量,通过选择的模式来配置DecimalFormat

6. Conclusion

6.结语

In this article, we briefly explored different ways of number formatting in Java. As we can see, there’s no one best way to do this. Many approaches can be used, as each of them have their own characteristics.

在这篇文章中,我们简要地探讨了Java中数字格式化的不同方式。正如我们所看到的,没有一种最好的方法可以做到这一点。许多方法都可以使用,因为它们各自都有自己的特点。

As always, the code for these examples is available over on GitHub.

像往常一样,这些例子的代码可以在GitHub上找到over