Hướng dẫn về java.util.Formatter

1. Khái quát chung

Trong bài viết này, chúng ta sẽ thảo luận về định dạng chuỗi trong Java bằng cách sử dụng lớp java.util.Formatter , lớp này cung cấp hỗ trợ cho việc căn chỉnh và căn chỉnh bố cục.

2. Cách sử dụng bộ định dạng

Nhớ printf của C không? Định dạng một chuỗi trong Java rất giống nhau.

Phương thức format () của Formatter được hiển thị thông qua một phương thức tĩnh từ lớp String . Phương thức này chấp nhận một Chuỗi mẫu và danh sách các đối số để điền vào mẫu với:

String greetings = String.format( "Hello Folks, welcome to %s !", "Baeldung");

Chuỗi kết quả là:

"Hello Folks, welcome to Baeldung !"

Mẫu là một Chuỗi có chứa một số văn bản tĩnh và một hoặc nhiều bộ chỉ định định dạng, cho biết đối số nào sẽ được đặt ở vị trí cụ thể.

Trong trường hợp này, có một chỉ định định dạng duy nhất % s , được thay thế bằng đối số tương ứng.

3. Định dạng chỉ định

3.1. Cú pháp chung

Cú pháp của định dạng specifiers cho chung, nhân vật,Numeric loại là:

%[argument_index$][flags][width][.precision]conversion

Đối số chỉ định_index , cờ, chiều rộngđộ chính xác là tùy chọn.

  • argument_index phần là một số nguyên i - chỉ ra rằng thứ i lập luận từ danh sách đối số nên được sử dụng ở đây
  • cờ là một tập hợp các ký tự được sử dụng để sửa đổi định dạng đầu ra
  • width là một số nguyên dương cho biết số ký tự tối thiểu được ghi vào đầu ra
  • độ chính xác là một số nguyên thường được sử dụng để hạn chế số lượng ký tự, mà hành vi cụ thể của chúng phụ thuộc vào chuyển đổi
  • là phần bắt buộc. Đó là một ký tự cho biết cách định dạng đối số. Tập hợp các chuyển đổi hợp lệ cho một đối số nhất định phụ thuộc vào kiểu dữ liệu của đối số

Trong ví dụ của chúng tôi ở trên, nếu chúng tôi muốn chỉ định số lượng của một đối số một cách rõ ràng, chúng tôi có thể viết nó bằng cách sử dụng các chỉ số đối số 1 $2 $ .

Cả hai đều là đối số thứ nhất và thứ hai tương ứng:

String greetings = String.format( "Hello %2$s, welcome to %1$s !", "Baeldung", "Folks");

3.2. Đối với Date / Time Đại diện

%[argument_index$][flags][width]conversion

Một lần nữa, đối số_index, cờchiều rộng là tùy chọn.

Hãy lấy một ví dụ để hiểu điều này:

@Test public void whenFormatSpecifierForCalendar_thenGotExpected() { Calendar c = new GregorianCalendar(2017, 11, 10); String s = String.format( "The date is: %tm %1$te,%1$tY", c); assertEquals("The date is: 12 10,2017", s); }

Ở đây, đối với mọi mã định dạng, đối số thứ nhất sẽ được sử dụng, do đó 1 $ . Ở đây nếu chúng ta bỏ qua đối số_index cho mã định dạng thứ 2 và thứ 3, nó sẽ cố gắng tìm 3 đối số, nhưng chúng ta cần sử dụng cùng một đối số cho cả 3 mã định dạng.

Vì vậy, sẽ ổn nếu chúng ta không chỉ định đối số _index cho cái đầu tiên, nhưng chúng ta cần chỉ định nó cho hai cái còn lại.

Các lá cờ ở đây được tạo thành từ hai nhân vật. Trong đó ký tự đầu tiên luôn là 't' hoặc 'T' . Ký tự thứ hai phụ thuộc vào phần Lịch sẽ được hiển thị.

Trong ví dụ của chúng tôi, các chỉ định định dạng đầu tiên tm , cho biết tháng được định dạng dưới dạng hai chữ số, te cho biết ngày trong tháng và tY cho biết Năm được định dạng là bốn chữ số.

3.3. Định dạng chỉ định mà không có đối số

%[flags][width]conversion

Các cờ tùy chọn và chiều rộng giống như được định nghĩa trong các phần trên.

Chuyển đổi bắt buộc là một ký tự hoặc Chuỗi chỉ ra nội dung sẽ được chèn vào đầu ra. Hiện tại, chỉ có thể in '%' và dòng mới 'n' bằng cách sử dụng:

@Test public void whenNoArguments_thenExpected() { String s = String.format("John scored 90%% in Fall semester"); assertEquals("John scored 90% in Fall semester", s); } 

Định dạng bên trong () , nếu chúng ta muốn in '%' - chúng ta cần thoát nó bằng cách sử dụng '%%' .

4. Chuyển đổi

Bây giờ chúng ta hãy đi sâu vào từng chi tiết của cú pháp Định dạng chỉ định, bắt đầu bằng một chuyển đổi . Lưu ý rằng bạn có thể tìm thấy tất cả các chi tiết trong javadocs của Formatter .

Như chúng ta đã nhận thấy trong các ví dụ trên, phần chuyển đổi là bắt buộc trong tất cả các mã định dạng và nó có thể được chia thành nhiều loại.

Chúng ta hãy xem xét từng cái bằng cách lấy ví dụ.

4.1. Chung

Được sử dụng cho bất kỳ loại đối số nào. Các chuyển đổi chung là:

  1. 'b' hoặc 'B' - cho các giá trị Boolean
  2. 'h' hoặc 'H' - dành cho HashCode
  3. 's' hoặc 'S' - đối với Chuỗi , nếu null , nó sẽ in ra "null", else arg.toString ()

Bây giờ chúng tôi sẽ cố gắng hiển thị các giá trị booleanString , sử dụng các chuyển đổi tương ứng:

@Test public void givenString_whenGeneralConversion_thenConvertedString() { String s = String.format("The correct answer is %s", false); assertEquals("The correct answer is false", s); s = String.format("The correct answer is %b", null); assertEquals("The correct answer is false", s); s = String.format("The correct answer is %B", true); assertEquals("The correct answer is TRUE", s); }

4.2. Tính cách

Used for the basic types which represent Unicode characters: char, Character, byte, Byte, short, and Short. This conversion can also be used for the types int and Integer when the Character.isValidCodePoint(int) returns true for them.

It can be written as ‘c’ or ’C’ based on the case we want.

Let's try to print some characters:

@Test public void givenString_whenCharConversion_thenConvertedString() { String s = String.format("The correct answer is %c", 'a'); assertEquals("The correct answer is a", s); s = String.format("The correct answer is %c", null); assertEquals("The correct answer is null", s); s = String.format("The correct answer is %C", 'b'); assertEquals("The correct answer is B", s); s = String.format("The valid unicode character: %c", 0x0400); assertTrue(Character.isValidCodePoint(0x0400)); assertEquals("The valid unicode character: Ѐ", s); }

Let's take one more example of an invalid code point:

@Test(expected = IllegalFormatCodePointException.class) public void whenIllegalCodePointForConversion_thenError() { String s = String.format("The valid unicode character: %c", 0x11FFFF); assertFalse(Character.isValidCodePoint(0x11FFFF)); assertEquals("The valid unicode character: Ā", s); }

4.3. Numeric – Integral

These are used for Java integral types: byte, Byte, short, Short, int and Integer, long, Long, and BigInteger. There are three conversions in this category:

  1. ‘d' – for decimal number
  2. ‘o' – for octal number
  3. ‘X' or ‘x' – for hexadecimal number

Let's try to print each of these:

@Test public void whenNumericIntegralConversion_thenConvertedString() { String s = String.format("The number 25 in decimal = %d", 25); assertEquals("The number 25 in decimal = 25", s); s = String.format("The number 25 in octal = %o", 25); assertEquals("The number 25 in octal = 31", s); s = String.format("The number 25 in hexadecimal = %x", 25); assertEquals("The number 25 in hexadecimal = 19", s); }

4.4. Numeric – Floating Point

Used for Java floating-point types: float, Float, double, Double, and BigDecimal

  1. ‘e' or ‘E'formatted as a decimal number in computerized scientific notation
  2. ‘f'formatted as a decimal number
  3. ‘g' or ‘G'based on the precision value after rounding, this conversion formats into computerized scientific notation or decimal format

Let's try to print the floating point numbers:

@Test public void whenNumericFloatingConversion_thenConvertedString() { String s = String.format( "The computerized scientific format of 10000.00 " + "= %e", 10000.00); assertEquals( "The computerized scientific format of 10000.00 = 1.000000e+04", s); String s2 = String.format("The decimal format of 10.019 = %f", 10.019); assertEquals("The decimal format of 10.019 = 10.019000", s2); }

4.5. Other Conversions

  • Date/Time – for Java types which are capable of encoding a date or time: long, Long, Calendar, Date and TemporalAccessor. For this, we need to use prefixed ‘t' or ‘T', as we saw earlier
  • Percent – prints a literal ‘%' (‘\u0025')
  • Line Separator – prints a platform-specific line separator

Let's have a look at a simple example:

@Test public void whenLineSeparatorConversion_thenConvertedString() { String s = String.format("First Line %nSecond Line"); assertEquals("First Line \n" + "Second Line", s); }

5. Flags

Flags, in general, are used to format the output. Whereas in case of date and time, they are used to specify which part of the date is to be displayed, as we saw in the Section 4 example.

A number of flags are available, a list of which can be found in the documentation.

Let’s see a flag example to understand it’s usage. ‘-‘ is used to format the output as left justified:

@Test public void whenSpecifyFlag_thenGotFormattedString() { String s = String.format("Without left justified flag: %5d", 25); assertEquals("Without left justified flag: 25", s); s = String.format("With left justified flag: %-5d", 25); assertEquals("With left justified flag: 25 ", s); }

6. Precision

For general conversions, precision is just the maximum number of characters to be written to the output. Whereas, f or the floating-point conversions the precision is the number of digits after the radix point.

The first statement is an example of precision with floating-point numbers, and the second one with general conversions:

@Test public void whenSpecifyPrecision_thenGotExpected() { String s = String.format( "Output of 25.09878 with Precision 2: %.2f", 25.09878); assertEquals("Output of 25.09878 with Precision 2: 25.10", s); String s2 = String.format( "Output of general conversion type with Precision 2: %.2b", true); assertEquals("Output of general conversion type with Precision 2: tr", s2); }

7. Argument Index

As mentioned previously, theargument_index is an integer that indicates the position of the argument in the argument list. 1$ indicates the first argument, 2$ the second argument, and so on.

Also, there is another way to reference arguments by position, by using the ‘<‘ (‘\u003c') flag, which means the argument from the previous format specifier will be re-used. For example, these two statements would produce the identical output:

@Test public void whenSpecifyArgumentIndex_thenGotExpected() { Calendar c = Calendar.getInstance(); String s = String.format("The date is: %tm %1$te,%1$tY", c); assertEquals("The date is: 12 10,2017", s); s = String.format("The date is: %tm %
    

8. Other Ways of Using Formatter

Till now we saw the use of format() method of the Formatter class. We can also create a Formatter instance, and use that to invoke the format() method.

We can create an instance by passing in an Appendable, OutputStream, File or file name. Based on this, the formatted String is stored in an Appendable, OutputStream, File respectively.

Let's see an example of using it with an Appendable. We can use it with others in the same way.

8.1. Using Formatter With Appendable

Let's create a StringBuilder instance sb, and create a Formatter using it. Then we'll invoke format() to format a String:

@Test public void whenCreateFormatter_thenFormatterWithAppendable() { StringBuilder sb = new StringBuilder(); Formatter formatter = new Formatter(sb); formatter.format("I am writting to a %s Instance.", sb.getClass()); assertEquals( "I am writting to a class java.lang.StringBuilder Instance.", sb.toString()); }

9. Conclusion

In this article, we saw the formatting facilities provided by the java.util.Formatter class. We saw various syntax that can be used to format the String and the conversion types that can be used for different data types.

As usual, the code for the examples we saw can be found over on Github.