Java中的格式化输出

Wesley13
• 阅读 770

说在前面:本文大部分内容和代码来自《Thinking in Java》。这本书真的是一本好书,强烈推荐。

在Java SE5(很久很久以前的版本)引入了format方法,这个方法跟C的printf方法很像。首先用个简单例子说明下如何使用format方法。

public static void main(String[] args) {
    int x = 5;
    double y = 5.129867;
    //旧的方式
    System.out.println("Row 1: [" + x + " " + y + "]");
    //新的方式
    System.out.format("Row 1: [%d %f]\n", x, y);
    //或
    System.out.printf("Row 1: [%d %f]\n", x, y);
}

输出结果

Row 1: [5 5.129867]
Row 1: [5 5.129867]
Row 1: [5 5.129867]

使用很简单,一个简单的格式化字符串,加上一串参数即可。formatprintf是等价的。我们可以看下printf方法的实现。

public PrintStream printf(String format, Object ... args) {
    return format(format, args);
}

再来看下 format方法的实现

private Formatter formatter;
……
public PrintStream format(String format, Object ... args) {
    try {
        synchronized (this) {
            ensureOpen();
            if ((formatter == null)
                || (formatter.locale() != Locale.getDefault()))
                formatter = new Formatter((Appendable) this);
            formatter.format(Locale.getDefault(), format, args);
        }
    } catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    } catch (IOException x) {
        trouble = true;
    }
    return this;
}

可以看到,format是通过Formatter类来实现内容格式化的。

在Java中,所有新的格式化功能都由java.util.Formatter类处理,可以将Formatter看作一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。当你创建一个Formatter 对象的时候,需要向其构造器传递一些信息,告诉它最终的结果将向哪里输出。

再看一个例子,这次我们不直接使用 System.out.format,而是使用 java.util.Formatter来实现格式化输出内容的需求:

public class Turtle {
    private String name;
    private Formatter f;
    public Turtle(String name, Formatter f){
        this.name = name;
        this.f = f;
    }
    public void move(int x, int y){
        f.format("%s The Turtle is at (%d, %d)\n", name, x, y);
    }
    public static void main(String[] args) {
        Turtle tommy = new Turtle("Tommy", new Formatter(System.out));
        tommy.move(0, 0);
        tommy.move(3, 2);
        tommy.move(7, 2);
    }
}

输出结果:

Tommy The Turtle is at (0, 0)
Tommy The Turtle is at (3, 2)
Tommy The Turtle is at (7, 2)

Formatter的构造器可以接受多种输出目的地,比如上例中的PrintStream,或者OutputStreamFile等。有兴趣的可以查看Formatter的构造器。

看到这里你可能会想:在上面的例子中,只是简单的输出字符串句子,以前常用的字符串拼接也可以做到,而且并没有多麻烦呀?

那我们现在来看下Formatter的更强大的地方:控制空格与对齐

解释再多,不如来一个实例,我们看例子:

public class Receipt {
    private double total = 0;
    private Formatter f = new Formatter(System.out);
    public void printTitle(){
        f.format("%-15s %5s %10s\n", "Item", "Qty", "Price");
        f.format("%-15s %5s %10s\n", "----", "---", "-----");
    }
    public void print(String name, int qty, double price){
        f.format("%-15.15s %5d %10.2f\n", name, qty, price);
        total = total + price;
    }
    public void printTotal(){
        f.format("%-15s %5s %10.2f\n", "Tax", "", total*0.06);
        f.format("%-15s %5s %10s\n", "", "", "-----");
        f.format("%-15s %5s %10.2f\n", "Total", "", total*1.06);
    }
    public static void main(String[] args) {
        Receipt receipt = new Receipt();
        receipt.printTitle();
        receipt.print("Jack's Magic Beans", 4, 4.25);
        receipt.print("Princess Peas", 3, 5.1);
        receipt.print("Three Bears Proridge", 1, 14.29);
        receipt.printTotal();
    }
}

输出结果:

Item              Qty      Price
----              ---      -----
Jack's Magic Be     4       4.25
Princess Peas       3       5.10
Three Bears Pro     1      14.29
Tax                         1.42
                           -----
Total                      25.06

是不是很整齐?通过简洁的语法,Formatter提供了对空格与对齐的强大控制能力。

看完例子,我们来解释下上面的格式化字符串“%-15s %5s %10.2f\n”是啥意思。以下是其抽象的语法:

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

最常见的就是通过width来控制一个域的大小。比如“%-15s”中的15。默认情况下,数据是右对齐,不过可以通过使用“-”来改变对齐方向。precision则有点特别,首先该值前面必须带小数点。比如“%10.2f”;其次应用于不同类型的数据转换时,precision的意义也不同。应用于String时,它表示打印String时输出字符的最大数量。而在将precison应用于浮点数时,则表示小数部分要显示出来的位数(默认是6位小数),如果小数位数过多则舍入,太少则在尾部补零。应用于整数,触发异常,因为整数没有小数部分。

最后补充下常用的类型转换字符:

类型转换字符表      
--------------------
d    整数型(十进制)      
c    Unicode字符     
b    Boolean值      
s    String        
f    浮点数(十进制)      
e    浮点数(科学计数)     
x    整数(十六进制)      
h    散列码(十六进制)     
%    字符“%”
点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java 获取当前时间精确到毫秒 格式化
方法1:newSimpleDateFormat(“yyyyMMddHHmmssSSS”).format(newDate());方法2:newSimpleDateFormat(“yyyyMMddHH:mm:ss:SSS”).format(newDate());一.获取当前系统时间和日期并格式化输出:i
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
红橙Darren 红橙Darren
3年前
C进阶 - 内存四驱模型
一.内存四驱模型不知我们是否有读过《深入理解java虚拟机》这本书,强烈推荐读一下。在java中我们将运行时数据,分为五个区域分别是:程序计数器,java虚拟机栈,本地方法栈,java堆,方法区。在c/c中我们将运行时数据,分为四个区域分别是:栈区,堆区,数据区,代码区。我们详细来介绍下:1.栈区:由编译器自动分配释放,存放函数的
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Easter79 Easter79
3年前
String.format方法使用
转自  https://blog.csdn.net/u010137760/article/details/82869637 1.代码中简单使用2.源码调用的方法3.相关类Formatter3.1可选的参数索引3.2可选的标记3.3可选的宽度3.4可选的精度3.5强制类型转换3.1非日期/时间转换类型
Stella981 Stella981
3年前
Python字符串格式化
1.简单运用字符串类型格式化采用format()方法,基本使用格式是:转自<模板字符串.format(<逗号分隔的参数)调用format()方法后会返回一个新的字符串,参数从0开始编号。"{}:计算机{}的CPU占用率为{}%。".format("20161231","PYTHON",10)Out\10\:'2
Wesley13 Wesley13
3年前
Java日期时间API系列30
  实际使用中,经常需要使用不同精确度的Date,比如保留到天2020042300:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyyMMdd),然后再解析为Date。Java8中可以用更多的方法来实现这个需求,下面使用三种方法:使用Format方法、 使用Of方法和使用With方法,性能对比,使用
Stella981 Stella981
3年前
C#语言和SQL Server数据库技术_前四章错题
1。在C中,如果让某个方法只能被它所在的程序集内的其他方法访问,可使用(C)修饰这个方法。(选择一项)A:privateB:protectedC:internalD:以上都不对2.下列关于String.Format()用法不正确的是(B)(选择一项)A:String.Format(“今天是周{0}”,1)B:String
Wesley13 Wesley13
3年前
Java构造器就是这么简单!
前言理解构造器之前,首先我们需要了解Java中为什么要引入构造器,以及构造器的作用。在很久之前,程序员们编写C程序总会忘记初始化变量(这真的是一件琐碎但必须的事),C引入了构造器(constructor)的概念,这是一个在创建对象时被自动调用的特殊方法。Java也采用了构造器。一、构造器的引入引入构造器帮助我们解决了哪
Wesley13 Wesley13
3年前
JAVA字符串格式化
原文地址:https://blog.csdn.net/lonely\_fireworks/article/details/7962171常规类型的格式化String类的format()方法用于创建格式化的字符串以及连接多个字符串对象。熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处。format()方法有两种重载形式。