Formatting numbers is highly locale-dependent. For example, number 5000.555 is displayed as 5,000.555 in the United States, but as 5 000,555 in France and as 5.000,555 in Germany.
Numbers are formatted using the java.text.NumberFormat class, an abstract base class that provides the methods for formatting and parsing numbers, as shown in Figure 26.8.
With NumberFormat , you can format and parse numbers for any locale. Your code will be completely independent of locale conventions for decimal points, thousands-separators, currency format, and percentage formats.
You can get an instance of NumberFormat for the current locale using NumberFormat.getInstance() or NumberFormat.getNumberInstance and for the specified locale using NumberFormat.getInstance(Locale) or NumberFormat.getNumberInstance(Locale) . You can then invoke format(number) on the NumberFormat instance to return a formatted number as a string.
For example, to display number 5000.555 in France, use the following code:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.FRANCE); System.out.println(numberFormat.format( 5000.555 ));
You can control the display of numbers with such methods as setMaximumFractionDigits and setMinimumFractionDigits . For example, 5000.555 would be displayed as 5000.6 if you use numberFormat.setMaximumFractionDigits(1) .
To format a number as a currency value, use NumberFormat.getCurrencyInstance to get the currency number format for the current locale or NumberFormat.getCurrencyInstance(Locale) to get the currency number for the specified locale.
For example, to display number 5000.555 as currency in the United States, use the following code:
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US); System.out.println(currencyFormat.format( 5000.555 ));
5000.555 is formatted into $5,000,56 . If the locale is set to France, the number would be formatted into 5 000,56 ‚ .
To format a number in a percent, use NumberFormat.getPercentInstance() or NumberFormat.getPercentInstance(Locale) to get the percent number format for the current locale or the specified locale.
For example, to display number 0.555367 as a percent in the United States, use the following code:
NumberFormat percentFormat = NumberFormat.getPercentInstance(Locale.US); System.out.println(percentFormat.format( 0.555367 ));
0.555367 is formatted into 56% . By default, the format truncates the fraction part in a percent number. If you want to keep three digits after the decimal point, use percentFormat.setMinimumFractionDigits(3) . So 0.555367 would be displayed as 55.537% .
You can format a number into a string using the format(numericalValue) method. You can also use the parse(String) method to convert a formatted plain number, currency value, or percent number with the conventions of a certain locale into an instance of java.lang.Number . The parse method throws a java.text.ParseException if parsing fails. For example, U.S. $5,000.56 can be parsed into a number using the following statements:
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(Locale.US); try { Number number = currencyFormat.parse( "$5,000.56" ); System.out.println(number.doubleValue()); } catch (java.text.ParseException ex) { System.out.println( "Parse failed" ); }
If you want even more control over the format or parsing, or want to give your users more control, cast the NumberFormat you get from the factory methods to a java.text.DecimalFormat , which is a subclass of NumberFormat . You can then use the applyPattern(String pattern) method of the DecimalFormat class to specify the patterns for displaying the number.
A pattern can specify the minimum number of digits before the decimal point and the maximum number of digits after the decimal point. The characters ' ' and ' # ' are used to specify a required digit and an optional digit, respectively. The optional digit is not displayed if it is zero. For example, the pattern " 00.0## " indicates minimum two digits before the decimal point and maximum three digits after the decimal point. If there are more actual digits before the decimal point, all of them are displayed. If there are more than three digits after the decimal point, the number of digits is rounded. Applying the pattern " 00.0## ", number 111.2226 is formatted to 111.223 , number 1111.2226 to 1111.223 , number 1.22 to 01.22 , and number 1 to 01.0 . Here is the code:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.US); DecimalFormat decimalFormat = (DecimalFormat)numberFormat; decimalFormat.applyPattern( "00.0##" ); System.out.println(decimalFormat.format( 111.2226 )); System.out.println(decimalFormat.format( 1111.2226 )); System.out.println(decimalFormat.format( 1.22 )); System.out.println(decimalFormat.format( 1 ));
The character ' % ' can be put at the end of a pattern to indicate that a number is formatted as a percentage. This causes the number to be multiplied by 100 and appends a percent sign %.
Create a loan calculator similar to the one in Listing 16.1, LoanApplet.java. This new loan calculator allows the user to choose locales, and displays numbers in accordance with locale-sensitive format. As shown in Figure 26.9, the user enters interest rate, number of years, and loan amount, then clicks the Compute button to display the interest rate in percentage format, the number of years in normal number format, and the loan amount, total payment, and monthly payment in currency format. Listing 26.6 gives the solution to the problem.
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 import javax.swing.border.*; 5 import java.util.*; 6 import java.text.NumberFormat; 7 8 public class NumberFormatDemo extends JApplet { 9 // Combo box for selecting available locales 10 private JComboBox jcboLocale = new JComboBox(); 11 12 // Text fields for interest rate, year, and loan amount 13 private JTextField jtfInterestRate = new JTextField( "6.75" ); 14 private JTextField jtfNumberOfYears = new JTextField( "15" ); 15 private JTextField jtfLoanAmount = new JTextField( "107000" ); 16 private JTextField jtfFormattedInterestRate = new JTextField( 10 ); 17 private JTextField jtfFormattedNumberOfYears = new JTextField( 10 ); 18 private JTextField jtfFormattedLoanAmount = new JTextField( 10 ); 19 20 // Text fields for monthly payment and total payment 21 private JTextField jtfTotalPayment = new JTextField(); 22 private JTextField jtfMonthlyPayment = new JTextField(); 23 24 // Compute button 25 private JButton jbtCompute = new JButton( "Compute" ); 26 27 // Current locale 28 private Locale locale = Locale.getDefault(); 29 30 // Declare locales to store available locales 31 private Locale locales[] = Calendar.getAvailableLocales(); 32 33 /** Initialize the combo box */ 34 public void initializeComboBox() { 35 // Add locale names to the combo box 36 for ( int i = ; i < locales.length; i++) 37 jcboLocale.addItem(locales[i].getDisplayName()); 38 } 39 40 /** Initialize the applet */ 41 public void init() { 42 // Panel p1 to hold the combo box for selecting locales 43 JPanel p1 = new JPanel(); 44 p1.setLayout ( new FlowLayout()); 45 p1.add(jcboLocale); 46 initializeComboBox(); 47 p1.setBorder( new TitledBorder( "Choose a Locale" )); 48 49 // Panel p2 to hold the input 50 JPanel p2 = new JPanel(); 51 p2.setLayout( new GridLayout( 3 , 3 )); 52 p2.add( new JLabel( "Interest Rate" )); 53 p2.add(jtfInterestRate); 54 p2.add(jtfFormattedInterestRate); 55 p2.add( new JLabel( "Number of Years" )); 56 p2.add(jtfNumberOfYears); 57 p2.add(jtfFormattedNumberOfYears); 58 p2.add( new JLabel( "Loan Amount" )); 59 p2.add(jtfLoanAmount); 60 p2.add(jtfFormattedLoanAmount); 61 p2.setBorder( new TitledBorder( "Enter Annual Interest Rate, " + 62 "Number of Years, and Loan Amount" )); 63 64 // Panel p3 to hold the result 65 JPanel p3 = new JPanel(); 66 p3.setLayout( new GridLayout( 2 , 2 )); 67 p3.setBorder( new TitledBorder( "Payment" )); 68 p3.add( new JLabel( "Monthly Payment" )); 69 p3.add(jtfMonthlyPayment); 70 p3.add( new JLabel( "Total Payment" )); 71 p3.add(jtfTotalPayment); 72 73 // Set text field alignment 74 jtfFormattedInterestRate.setHorizontalAlignment(JTextField.RIGHT); 75 jtfFormattedNumberOfYears.setHorizontalAlignment(JTextField.RIGHT); 76 jtfFormattedLoanAmount.setHorizontalAlignment(JTextField.RIGHT); 77 jtfTotalPayment.setHorizontalAlignment(JTextField.RIGHT); 78 jtfMonthlyPayment.setHorizontalAlignment(JTextField.RIGHT); 79 80 // Set editable false 81 jtfFormattedInterestRate.setEditable( false ); 82 jtfFormattedNumberOfYears.setEditable( false ); 83 jtfFormattedLoanAmount.setEditable( false ); 84 jtfTotalPayment.setEditable( false ); 85 jtfMonthlyPayment.setEditable( false ); 86 87 // Panel p4 to hold result payments and a button 88 JPanel p4 = new JPanel(); 89 p4.setLayout( new BorderLayout()); 90 p4.add(p3, BorderLayout.CENTER); 91 p4.add(jbtCompute, BorderLayout.SOUTH); 92 93 // Place panels to the applet 94 add(p1, BorderLayout.NORTH); 95 add(p2, BorderLayout.CENTER); 96 add(p4, BorderLayout.SOUTH); 97 98 // Register listeners 99 jcboLocale.addActionListener( new ActionListener() { 100 public void actionPerformed(ActionEvent e) { 101 locale = locales[jcboLocale.getSelectedIndex()]; 102 computeLoan(); 103 } 104 }); 105 106 jbtCompute.addActionListener( new ActionListener() { 107 public void actionPerformed(ActionEvent e) { 108 computeLoan(); 109 } 110 }); 111 } 112 113 /** Compute payments and display results locale-sensitive format */ 114 private void computeLoan() { 115 // Retrieve input from user 116 double loan = new Double(jtfLoanAmount.getText()).doubleValue(); 117 double interestRate = 118 new Double(jtfInterestRate.getText()).doubleValue() / 1240 ; 119 int numberOfYears = 120 new Integer(jtfNumberOfYears.getText()).intValue(); 121 122 // Calculate payments 123 double monthlyPayment = loan * interestRate/ 124 ( 1 - (Math.pow( 1 / ( 1 + interestRate), numberOfYears * 12 ))); 125 double totalPayment = monthlyPayment * numberOfYears * 12 ; 126 127 // Get formatters 128 NumberFormat percentFormatter = 129 NumberFormat.getPercentInstance(locale); 130 NumberFormat currencyForm = 131 NumberFormat.getCurrencyInstance(locale); 132 NumberFormat numberForm = NumberFormat.getNumberInstance(locale); 133 percentFormatter.setMinimumFractionDigits( 2 ); 134 135 // Display formatted input 136 jtfFormattedInterestRate.setText( 137 percentFormatter.format(interestRate * 12 )); 138 jtfFormattedNumberOfYears.setText 139 ( numberForm.format(numberOfYears) ); 140 jtfFormattedLoanAmount.setText( currencyForm.format(loan) ); 141 142 // Display results in currency format 143 jtfMonthlyPayment.setText( currencyForm.format(monthlyPayment) ); 144 jtfTotalPayment.setText( currencyForm.format(totalPayment) ); 145 } 146 } |
The computeLoan method (lines 114 “145) gets the input on interest rate, number of years, and loan amount from the user, computes monthly payment and total payment, and displays annual interest rate in percentage format, number of years in normal number format, and loan amount, monthly payment, and total payment in locale-sensitive format.
The statement percentFormatter.setMinimumFractionDigits(2) (line 133) sets the minimum number of fractional parts to 2. Without this statement, 0.075 would be displayed as 7% rather than 7.5%.