java中格式化数值和货币

java中格式化数值和货币

(转自:http://hi.baidu.com/gacmotor/blog/item/b0abf950fdae4211377abe16.html)

java.text包允许通过与特定语言无关的方式格式化文本消息、日期和数 值。许多人配合MessageFormat类使用资源包来为用户本地化消息。更多的人似乎使用DateFormat和SimpleDateFormat类 来操作日期字符串,既用于输入也用于输出。最少见的用法似乎是使用NumberFormat类及其相关的子类DecimalFormat和 ChoiceFormat。在本月的讨论中,我们将研究一下这三个未得到充分利用的类以及Currency类,看看 J2SE 1.4 已经变得有多么的全球化。

数值格式化基类:NumberFormat
如 果您来自美国,您会在较大的数值中间放置逗号来表示千和百万(等等,每三个数值使用一个逗号)。对于浮点数,您将在整数部分和小数部分之间放置小数点。对 于金钱,货币符号$ 放在金额的前面。如果您从来没有到过美国以外的地方,可能就不会关心用元(¥)来格式化的日本货币,用英镑(£)来格式化的英国货币,或者用欧元( )来 表示的其他欧洲国家的货币。

对于那些我们确实关心的货币,我们可以使用NumberFormat及其相关的类来格式化它们。开发人员使用NumberFormat类来读取用户 输入的数值,并格式化将要显示给用户看的输出。

与DateFormat类似,NumberFormat是一个抽象类。您永远不会创建它的实例?D?D相反,您总是使用它的子类。虽然可以通过子类 的构造函数直接创建子类,不过NumberFormat类提供了一系列getXXXInstance()方法,用以获得不同类型的数值类的特定地区版本。 这样的方法共有五个:


getCurrencyInstance()
getInstance()
getIntegerInstance()
getNumberInstance()
getPercentInstance()
具体使用哪一个方法取决于您想要显示的数值类型(或者想要接受的输入类型)。每个方法都提供了两个版本?D?D一个版本适用于当前地区,另一个版本接受一 个Locale作为参数,以便可能地指定一个不同的地区。

在 J2SE 1.4中,NumberFormat新增的内容是getIntegerInstance()、getCurrency()和setCurrency()方 法。下面让我们研究一下新的getIntegerInstance()方法。稍后将会探讨 get/set 货币方法。

使用NumberFormat的基本过程是获得一个实例并使用该实例。挑选恰当的实例的确需要费一番思量。通常您不希望使用通用的 getInstance或者getNumberInstance()版本,因为您不确切知道您将会得到什么。相反,您会使用像 getIntegerInstance()这样的方法,因为您希望把某些内容显示为整数而不需要任何小数值。清单1展示了这一点,我们在其中把数值 54321显示为适合于美国和德国的格式。

清单 1. 使用 NumberFormat


import java.text.*;
import java.util.*;

public class IntegerSample {
public static void main(String args[]) {
   int amount = 54321;
   NumberFormat usFormat = NumberFormat.getIntegerInstance(Locale.US);
   System.out.println(usFormat.format(amount));
   NumberFormat germanFormat = NumberFormat
     .getIntegerInstance(Locale.GERMANY);
   System.out.println(germanFormat.format(amount));
}
}

运行该代码将产生如清单2所示的输出。注意第一种格式(美国)中的逗号分隔符和第二种格式中的点号分隔符。

清单 2. NumberFormat 输出


54,321

54.321

 

学习如何迭代 DecimalFormat 中的字符
虽然NumberFormat是一个抽象类,并且您将通过像getIntegerInstance()这样的各种方法来使用它的实例,但是 DecimalFormat类提供了该类的一个具体版本。您可以显式地指定字符模式,用以确定如何显示正数、负数、小数和指数。如果不喜欢用于不同地区的 预定义格式,您可以创建自己的格式。(在内部,或许NumberFormat使用的就是DecimalFormat。)基本的DecimalFormat 功能在 J2SE 平台的 1.4 版中并没有改变。改变之处在于添加了formatToCharacterIterator()、getCurrency()和setCurrency() 方法。

我们将快速浏览一下新的formatToCharacterIterator方法及其关联的NumberFormat.Field类。J2SE 1.4 引入了CharacterIterator的概念,它允许双向地遍历文本。对于formatToCharacterIterator,您将获得它的子接口 AttributedCharacterIterator,这个子接口允许您找出关于该文本的信息。

对于DecimalFormat 的情况 那 些属性是来自NumberFormat.Field 的键 通 过使用AttributedCharacterIterator , 您完全可以根据所产生的结果构造自己的字符串输出 清单3使用了一个百分数实例来提供一个简单的演示:

清单 3. 使用 formatToCharacterIterator()


import java.text.*;
import java.util.*;

public class DecimalSample {
public static void main(String args[]) {
double amount = 50.25;
NumberFormat usFormat = NumberFormat.getPercentInstance(Locale.US);
if (usFormat instanceof DecimalFormat) {
DecimalFormat decFormat = (DecimalFormat)usFormat;
AttributedCharacterIterator iter =
decFormat.formatToCharacterIterator(new Double(amount));
for (char c = iter.first();
c != CharacterIterator.DONE;
c = iter.next()) {
// Get map for current character
Map map = iter.getAttributes();
// Display its attributes
System.out.println("Char: " + c + " / " + map);
}
}
}
}

清单4显示了程序的输出(显示在一小段消息之后,以使其更易于阅读)。基本上,formatToCharacterIterator() 方 法的工作方式与调用format() 相同,只不过前者除了格式化输 出字符串外,还要使用属性来标记输出中的每个字符(例如,位于位置 X 处的字符是否为一个整数?)。将 50.25显示为百分数,在美国地区的输出为“5,025%”。通过检查输出 除“%”外的每个字符都是整数,包括冒 号 除了数值之外 逗号也被标记为一个分组分隔符,百分号被标记为一个百分数。每 个数字的属性都是一个java.util.Map ,其中每个属性被 显示为key=value (键=值)的形式。在存在多个属性的情况 下,属性列表中的属性之间用逗号分隔。

清单 4. formatToCharacterIterator() 输出


Char: 5 / {java.text.NumberFormat$Field(integer)=
java.text.NumberFormat$Field(integer)}
Char: , / {java.text.NumberFormat$Field(grouping separator)=
java.text.NumberFormat$Field(grouping separator),
java.text.NumberFormat$Field(integer)=
java.text.NumberFormat$Field(integer)}
Char: 0 / {java.text.NumberFormat$Field(integer)=
java.text.NumberFormat$Field(integer)}
Char: 2 / {java.text.NumberFormat$Field(integer)=
java.text.NumberFormat$Field(integer)}
Char: 5 / {java.text.NumberFormat$Field(integer)=
java.text.NumberFormat$Field(integer)}
Char: % / {java.text.NumberFormat$Field(percent)=
java.text.NumberFormat$Field(percent)}

基于值范围和 ChoiceFormat确定消息
ChoiceFormat NumberFormat 的另一个具体子类。它的定义和行为在 J2SE 1.4 中没有改变。ChoiceFormat 并不会真正帮助您格式化数 值,但它的确允许您自定义与某个值关联的文本。在最简单的情况下,我们可以设想一下显示出错消息的情况。如果存在导致失败的单个原因,您希望使用单词 “is”。如果有两个或者多个原因,您希望使用单词“are”。如清单5所示,ChoiceFormat 允 许您把一系列的值映射为不同的文本字符串。

ChoiceFormat 类通常与MessageFormat 类一起使用,以产生与语言无关的拼接起来的消息。这里没有说明的 是如何使用ResourceBundle (它通常与ChoiceFormat 一起使用)来获得那些字符串。关于如何使用资源包的信息 请 参见参考资料 ;特别地,“Java 国际化基础”教程提供了关于这方面的深入讨论

清单 5. 使用 ChoiceFormat


import java.text.*;
import java.util.*;
public class ChoiceSample {
public static void main(String args[]) {
   double limits[] = { 0, 1, 2 };
   String messages[] = { "is no content", "is one item", "are many items" };
   ChoiceFormat formats = new ChoiceFormat(limits, messages);
   MessageFormat message = new MessageFormat("There {0}.");
   message.setFormats(new Format[] { formats });
   for (int i = 0; i < 5; i++) {
    Object formatArgs[] = { new Integer(i) };
    System.out.println(i + ": " + message.format(formatArgs));
   }
}
}

 


执行该程序将产生如清单6所示的输出:

清单 6. ChoiceFormat 输出


0: There is no content.
1: There is one item.
2: There are many items.
3: There are many items.
4: There are many items.

使用 Currency 进行货币计算
前面提到过的getCurrency()和setCurrency()方法返回新的java.util.Currency类的一个实例。这个类允许访问不 同国家的ISO 4217货币代码。虽然自从getCurrencyInstance()引入以来您就能配合NumberFormat一起使用它,然而除了它们的数字显示 外,您永远不能获得或显示某个地区的货币符号。有了Currency类,现在很容易就可以做到这一点。

正如前面提到过的,货币代码来自ISO4217。通过传入某个国家的Locale或者货币的实际字母代 码,Currency.getInstance()将返回一个有效的Currency对象。NumberFormat的getCurrency()方法将 在创建特定地区的货币实例之后做同样的事情。清单7显示了如何获得货币实例,以及如何格式化将要显示为货币的数值。记住这些转换仅用于显示。如果需要在货 币之间转换金额,应该在确定如何显示值之前进行转换。

清单 7. 使用 getCurrencyInstance() 和 Currency


import java.text.*;
import java.util.*;
import java.awt.*;
import javax.swing.*;

public class CurrencySample {
public static void main(String args[]) {
   StringBuffer buffer = new StringBuffer(100);
   Currency dollars = Currency.getInstance("USD");
   Currency pounds = Currency.getInstance(Locale.UK);
   buffer.append("Dollars: ");
   buffer.append(dollars.getSymbol());
   buffer.append("/n");
   buffer.append("Pound Sterling: ");
   buffer.append(pounds.getSymbol());
   buffer.append("/n-----/n");
   double amount = 5000.25;
   NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
   buffer.append("Symbol: ");
   buffer.append(usFormat.getCurrency().getSymbol());
   buffer.append("/n");
   buffer.append(usFormat.format(amount));
   buffer.append("/n");
   NumberFormat germanFormat = NumberFormat
     .getCurrencyInstance(Locale.GERMANY);
   buffer.append("Symbol: ");
   buffer.append(germanFormat.getCurrency().getSymbol());
   buffer.append("/n");
   buffer.append(germanFormat.format(amount));
   JFrame frame = new JFrame("Currency");
   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   JTextArea ta = new JTextArea(buffer.toString());
   JScrollPane pane = new JScrollPane(ta);
   frame.getContentPane().add(pane, BorderLayout.CENTER);
   frame.setSize(200, 200);
   frame.show();
}
}

遗憾的是,为欧元或者英镑返回的货币符号不是实际的符号,而是三位的货币代码(来自 ISO 4217)。然而在使用getCurrencyInstance()的情况下,实际的符号将会显示出来,如图1所示。

图 1. 看见实际的货币符号


结束语
对于软 件全球化来说,所需做的不仅仅是自定义文本消息。虽然把文本消息转移到资源包中至少完成了工作的一半,但是也不要忘了处理与地区密切相关的数值和货币显 示。并不是每个人都像在美国一样使用冒号和点号来进行数字显示,每个人都必须处理自己的货币细节。虽然我们不必依赖像 $$$.99 这样的老式 COBOL图形字符串,但是通过使用特定于地区的NumberFormat实例,您可以使自己的程序更加国际化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值