java format

2021/02/18 Java初级进阶 共 13438 字,约 39 分钟
闷骚的程序员

1. java中的format

有时候,我们需要对程序中的文本、数字、日期等类型进行某种格式化,以适应我们自身的阅读和显式习惯。
在java中进行格式化的类主要是Format类。
Format类主要有3个子类:

  1. MessageFormat类(消息文本格式化类)。
  2. NumberFormat抽象类(数字格式化类)。
  3. DateFormat抽象类(日期格式化类)。

2. MessageFormat

MessageFormat是Format的子类,在java.text包中,专门用来格式化字符串文本。
其核心方法如下:

public static String format(String pattern, Object ... arguments);

其中第1个参数表示要操作的字符串文本,第2个参数表示输入参数可以是任意多个或者0个。
该方法的核心功能就是格式化字符串,使用实际参数替换字符串文本中的占位符{0}之类的。

案例代码如下:

package javase.demo18.classlibray.base;
import java.text.MessageFormat;

// MessageFormat进行文本格式化
public class Demo16StudyMessageFormat {
    public static void main(String[] args) {
        String target = "hello,{0}.my home is {1}!";
        System.out.println(target);
        String format = MessageFormat.format(target, "Eric", "西安");
        System.out.println(format);
        target = "hello,{2}.my home is {3}!";
        format = MessageFormat.format(target, "Eric", "西安");
        System.out.println(format);
    }
}

运行结果如下:

hello,{0}.my home is {1}!
hello,Eric.my home is 西安!
hello,{2}.my home is {3}!

总结:

  1. MessageFormat类的format()方法接收2个参数,第1个参数表示要格式化的目标字符串,第2个参数是个可变参数,表示传入的用于替换字符串中占位符的参数,可以是无数个或者0个。
  2. 字符串中的占位符使用形式必须遵守{index}的形式,其中index表示要占位符的索引,从0开始匹配。此处占位符必须从{0},再到{1},{2}…以此类推。占位符的索引下标必须和format()方法的可变参数下标匹配上才会进行format操作。否则对于不匹配的占位符将不会进行任何format。

3. String类的format方法

String类本身也提供一个static的format()方法。定义如下:

public static String format(String format, Object... args) {
    return new Formatter().format(format, args).toString();
}

String类的format()方法用于创建格式化的字符串以及连接多个字符串对象。
熟悉C语言的同学应该记得C语言的sprintf()方法,两者有类似之处。
format()方法有两种重载形式:
format(String format, Object… args) 新字符串使用本地语言环境,制定字符串格式和参数生成格式化的新字符串。
format(Locale locale, String format, Object… args) 使用指定的语言环境,指定字符串格式和参数生成格式化的字符串。
该方法用于显示不同转换符,实现不同数据类型到字符串的转换,如下所示:

%s   字符串类型
%c   字符类型
%b   布尔类型
%d   整数类型(十进制)
%x   整数类型(十六进制)
%o   整数类型(八进制)
%f   浮点类型
%a   十六进制浮点类型
%e   指数类型
%g   通用浮点类型(f和e类型中较短的)
%h   散列码
%%   百分比类型
%n   换行符
%tx  日期与时间类型(x代表不同的日期与时间转换符

同时,System.out.printf()方法也完成了对String类的format()方法的调用,使得在直接输出String字符串时,对于格式化更加简便。
注意:只有printf()方法可以完成对字符串输出的同时进行格式化,print()和println()方法并没有此功能。

案例如下:

package zeh.myjavase.code10str.string;

public class Demo10StringFormat {
    public static void main(String[] args) {
        String str = null;
        str = String.format("Hi,%s", "王力");
        System.out.println(str);
        str = String.format("Hi,%s:%s.。。。。%s", "王南", "王力", "王张");
        System.out.println(str);

        //printf()方法是重载的对应format的方法
        //%c表示字符占位
        //%n表示换行占位,不用指定换行符,自动换行
        //%b表示布尔占位
        //%d表示数字占位
        //%x表示16进制占位
        //%o表示8进制占位
        //%f表示float占位
        System.out.printf("字母a的大写是:%c %n", 'A');
        System.out.printf("3>7的结果是:%b %n", 3 > 7);
        System.out.printf("100的一半是:%d %n", 100 / 2);
        System.out.printf("100的16进制数是:%x %n", 100);
        System.out.printf("100的8进制数是:%o %n", 100);
        System.out.printf("50元的书打8.5折扣是:%f 元%n", 50 * 0.85);
        System.out.printf("上面价格的16进制数是:%a %n", 50 * 0.85);
        System.out.printf("上面价格的指数表示:%e %n", 50 * 0.85);
        System.out.printf("上面价格的指数和浮点数结果的长度较短的是:%g %n", 50 * 0.85);
        System.out.printf("上面的折扣是%d%% %n", 85);
        System.out.printf("字母A的散列码是:%h %n", 'A');

        //print和println方法不能使用format
        System.out.print("12345678");
        System.out.println("12345678");
    }
}

运行结果:

Hi,王力
Hi,王南:王力.。。。。王张
字母a的大写是:A 
3>7的结果是:false 
100的一半是:50 
100的16进制数是:64 
100的8进制数是:144 
50元的书打8.5折扣是:42.500000 元
上面价格的16进制数是:0x1.54p5 
上面价格的指数表示:4.250000e+01 
上面价格的指数和浮点数结果的长度较短的是:42.5000 
上面的折扣是85% 
字母A的散列码是:41 
1234567812345678

Process finished with exit code 0

4. NumberFormat抽象类,格式化数字

4.1 直接使用NumberFormat

NumberFormat表示数字格式化类,和DateFormat、MessageFormat类一样都是Format类的子类;
其中DateFormat和NumberFormat都是抽象类。
NumberFormat类还有个常用的子类:DecimalFormat类。
NumberFormat对数字进行格式化,只能指定不同的语言环境,按照语言环境的默认格式对数字进行格式化。
案例:

package zeh.myjavase.code18classlib.base;

import java.text.NumberFormat;
import java.util.Locale;

public class Demo13StudyNumberFormat {
	public static void main(String args[]) {
		// 使用当前语言环境格式化数字,当前的操作系统是中文语言环境,所以数字显示成了中国的数字格式化形式
		NumberFormat nf = null;
		// 返回当前环境默认语言的数字格式
		nf = NumberFormat.getInstance();
		System.out.println("格式化之后的数字:" + nf.format(10000000));
		System.out.println("格式化之后的数字:" + nf.format(1000.235));

		// 返回当前服务器上所有语言环境的数组
		Locale locale[] = NumberFormat.getAvailableLocales();
		for (int i = 0; i < locale.length; i++) {
			System.out.println(locale[i] + "、");
		}
		System.out.println("*************************************");

		// 实例化指定语言格式的NumberFormat
		NumberFormat nf2 = null;
		nf2 = NumberFormat.getInstance(new Locale("fr", "FR"));
		System.out.println("(法文语言环境下)格式化之后的数字:" + nf2.format(10000000));
		System.out.println("(法文语言环境下)格式化之后的数字:" + nf2.format(1000.235));
	}
}

运行结果:

格式化之后的数字:10,000,000
格式化之后的数字:1,000.235
、
ar_AE、
ar_JO、
ar_SY、
hr_HR、
fr_BE、
es_PA、
es_VE、
mt_MT、
bg、
zh_TW、
it、
ko、
uk、
lv、
da_DK、
es_PR、
vi_VN、
en_US、
sr_ME、
sv_SE、
en_SG、
es_BO、
ar_BH、
pt、
ar_SA、
sk、
ar_YE、
hi_IN、
ga、
en_MT、
fi_FI、
et、
cs、
sr_BA_#Latn、
sv、
el、
uk_UA、
fr_CH、
hu、
in、
es_AR、
ar_EG、
ja_JP_JP_#u-ca-japanese、
es_SV、
pt_BR、
be、
cs_CZ、
es、
is_IS、
ca_ES、
pl_PL、
tr、
sr_CS、
hr、
ms_MY、
lt、
es_ES、
bg_BG、
es_CO、
fr、
sq、
ja、
sr_BA、
es_PY、
is、
de、
es_EC、
es_US、
ar_SD、
en、
ro_RO、
en_PH、
ca、
ar_TN、
sr_ME_#Latn、
es_GT、
el_CY、
ko_KR、
sl、
es_MX、
ru_RU、
es_HN、
no_NO_NY、
zh_HK、
hu_HU、
th_TH、
ar_IQ、
es_CL、
ar_MA、
fi、
ga_IE、
mk、
tr_TR、
ar_QA、
et_EE、
sr__#Latn、
pt_PT、
fr_LU、
ar_OM、
th、
sq_AL、
es_DO、
es_CU、
ar、
ru、
en_NZ、
sr_RS、
de_CH、
es_UY、
ms、
el_GR、
iw_IL、
en_ZA、
th_TH_TH_#u-nu-thai、
hi、
fr_FR、
de_AT、
nl、
no_NO、
en_AU、
vi、
fr_CA、
lv_LV、
nl_NL、
de_LU、
es_CR、
ar_KW、
ar_LY、
sr、
it_CH、
mt、
da、
de_DE、
ar_DZ、
sk_SK、
it_IT、
lt_LT、
en_IE、
zh_SG、
en_CA、
ro、
nl_BE、
no、
pl、
zh_CN、
ja_JP、
de_GR、
sr_RS_#Latn、
iw、
en_IN、
ar_LB、
es_NI、
zh、
be_BY、
mk_MK、
sl_SI、
es_PE、
in_ID、
en_GB、
*************************************
(法文语言环境下)格式化之后的数字:10 000 000
(法文语言环境下)格式化之后的数字:1 000,235

4.2 DecimalFormat类对数字按照指定格式模板进行格式化

DecimalFormat类是NumberFormat类的子类;
与NumberFormat类相比,DecimalFormat类要比NumberFormat类更加方便,因为可以直接指定按用户自定义的方式进行格式化操作,与SimpleDateFormat类似。
Decimal格式化模板:

0:代表阿拉伯数字,每一个0表示一位阿拉伯数字,如果该位数字不存在则显示为0
#:代表阿拉伯数字,每一个#表示一位阿拉伯数字,如果该位不存在则不显示
.:小数点分隔符或者货币的小数分隔符
-:代表负号
,:分组分隔符
E:分隔科学计数法中的位数和指数
;:子模式边界,分隔整数和负数子模式
%:前缀或后缀,数字乘以100并显示为百分数
\u2030:前缀或后缀,数字乘以1000并显示为千分数

案例如下:
单独封装一个DecimalFormat实用类用来格式化数字:

package zeh.myjavase.code18classlib.base;

import java.text.DecimalFormat;

// 专门用来实例化DecimalFormat类对象
class Demo06FormatDemo {
    public void format1(String pattern, double value) {
        DecimalFormat df = null;
        // 按照指定的模板实例化DecimalFormat
        df = new DecimalFormat(pattern);
        // 对指定的数字按照指定的模板进行格式化
        String str = df.format(value);
        System.out.println("使用" + pattern + "模板格式化数字,格式化前:" + value + "-->" + str);
    }
}

调用上面封装的数字格式化类,传入指定数字和指定格式化模板进行数字的格式化:

package zeh.myjavase.code18classlib.base;

public class Demo06StudyDecimalFormat {
    public static void main(String args[]) {
        Demo06FormatDemo demo = new Demo06FormatDemo();
        demo.format1("###,###.###", 111222.34567);
        demo.format1("0000,000.000", 111222.34567);
        demo.format1("###,###.###¥", 111222.34567);
        demo.format1("000,000.000¥", 111222.34567);
        demo.format1("##.###%", 0.345678);// 使用百分数形式
        demo.format1("00.###%", 0.023456);// 使用百分数形式
        demo.format1("###.###\u2030", 0.3455667);// 使用千分数形式
    }
}

运行结果:

使用###,###.###模板格式化数字,格式化前:111222.34567-->111,222.346
使用0000,000.000模板格式化数字,格式化前:111222.34567-->0,111,222.346
使用###,###.###¥模板格式化数字,格式化前:111222.34567-->111,222.346¥
使用000,000.000¥模板格式化数字,格式化前:111222.34567-->111,222.346¥
使用##.###%模板格式化数字,格式化前:0.345678-->34.568%
使用00.###%模板格式化数字,格式化前:0.023456-->02.346%
使用###.###‰模板格式化数字,格式化前:0.3455667-->345.567‰

5. DateFormat抽象类

5.1 直接使用DateFormat

实际上java.util包中的Date对象取得是一个很准确的时间,但是因为不符合中国人的阅读习惯所以需要格式化一下。
DateFormat类专门根据指定的Locale语言环境对日期进行特定的格式化操作。
DateFormat类和MessageFormat类都是Format类的子类,专门用来格式化数据使用。
DateFormat类是抽象类,通过静态方法getDateInstance等取得其实例对象。
SimpleDateFormat类是DateFormat类的子类,比DateFormat更方便,可以自定义日期时间的格式化模板。
注意:DateFormat没法自定义模板去格式化日期时间,一般还是SimpleDateFormat用的多。
案例:

package zeh.myjavase.code18classlib.date;

import org.junit.Test;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class Demo06StudyDateAndDateFormat {

	@Test
	public void testDateFormat() {

		// 直接输出date对象,不格式化
		// 根据默认的日期时间显示格式进行显示
		System.out.println("直接输出date,按照 java 的默认格式显示日期:" + new Date());
		
		// 取得Date的DateFormat,只有日期。
		DateFormat df1 = DateFormat.getDateInstance();
		// 取得日期时间的DateFormat,有日期和时间,精确到秒。
		DateFormat df2 = DateFormat.getDateTimeInstance();
		
		// 格式化日期
		System.out.println("默认格式化后的日期:" + df1.format(new Date()));
		// 格式化日期时间
		System.out.println("默认格式化后的日期时间:" + df2.format(new Date()));

		// 指定Locale,显示中文环境下的日期时间显示格式
		// 缺点:DateFormat类虽然能够指定Locale显示中文,但是显示的格式仍然是默认的,而不是随心所欲自定义的格式
		// 取得日期,并指定显示风格
		DateFormat df3 = DateFormat.getDateInstance(DateFormat.YEAR_FIELD,
				new Locale("zh", "CN"));
		// 取得日期时间,并指定日期和时间的显示风格
		DateFormat df4 = DateFormat.getDateTimeInstance(DateFormat.YEAR_FIELD,
				DateFormat.ERA_FIELD, new Locale("zh", "CN"));
		// 根据中文Locale格式化日期
		System.out.println("根据中文环境格式化后的日期:" + df3.format(new Date()));
		// 根据中文locale格式化日期时间
		System.out.println("根据中文环境格式化后的日期时间:" + df4.format(new Date()));
	}
}

运行结果:

直接输出date,按照 java 的默认格式显示日期:Wed Nov 24 15:26:59 CST 2021
默认格式化后的日期:2021-11-24
默认格式化后的日期时间:2021-11-24 15:26:59
根据中文环境格式化后的日期:2021年11月24日
根据中文环境格式化后的日期时间:2021年11月24日 下午03时26分59秒 CST

5.2 使用子类SimpleDateFormat进行日期格式化

SimpleDateFormat类提供的日期格式化更加灵活,方便java的date类型和String类型之间的互相转换。
SimpleDateFormat类主要用于:将日期从一种格式转换成另外一种显示格式。只是日期格式的不同而已,日期本身的值不发生任何改变。
首先会定义一个字符串格式的日期和一个日期模板,字符串格式的日期和模板必须相对应才能提取出来;将指定的日期从字符串日期中提取出来后再转换成另外一种显示格式。

SimpleDateFormat类在使用中经常用于:
将String类型的日期和Date格式的日期进行互转。 通过中间模板进行提取。

  1. parse()方法用于从字符串日期中提取成Date类型的日期;
  2. format()用于将Date类型的日期格式化为指定的字符串类型。

支持的日期格式字符:

案例如下:

package zeh.myjavase.code18classlib.date;

import org.junit.Test;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo04StudyDateAndSimpleDateFormat {
    @Test
    public void testParse() throws ParseException {
        // 取得当前毫秒数,即自1970年后的毫秒数。
        System.out.println("当前毫秒数:" + System.currentTimeMillis());

        // 定义模板
        String pat = "yyyy-MM-dd";

        System.out.println("默认日期:" + new Date());
        // 根据格式化模板实例化SimpleDateFormat对象
        SimpleDateFormat format = new SimpleDateFormat(pat);

        String dateStr = "2018-09-03";
        // 根据日期字符串解析出指定格式的日期
        Date date = format.parse(dateStr);
        // 对指定格式的日期对象进行格式化
        String formatDate = format.format(date);
        System.out.println(date);
        System.out.println("对提取出来的日期对象格式化:" + formatDate);
    }

    @Test
    public void testFormat() {
        // 定义日期时间的字符串
        String strDate = "2018-10-19 10:11:30.234";
        // 准备第一个模板,与上面的字符串日期格式对应,可以将上面的日期数字按照该模板进行提取
        String pat1 = "yyyy-MM-dd hh:mm:ss.SSS";
        // 准备第二个模板,将按照第一个模板提取的日期数值按照第二个模板进行格式化
        String pat2 = "yyyy年MM月dd号  hh点mm分ss秒SSS毫秒";

        /* 实例化上述的两个模板对象 */
        SimpleDateFormat sdf1 = new SimpleDateFormat(pat1);
        SimpleDateFormat sdf2 = new SimpleDateFormat(pat2);

        Date date = null;
        try {
            // 从字符串日期中按照格式1提取出date对象
            date = sdf1.parse(strDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        String formatDate = sdf2.format(date);
        // 将提取出来的日期按照模板2进行格式化
        System.out.println("输出提取出来的日期对象格式化后的日期时间字符串:" + formatDate);
    }

    // 格式化当前日期时间
    @Test
    public void testFormatDate1() {
        Date date = new Date();// 实例化当前时间
        String pat1 = "yyyy-MM-dd hh:mm";
        SimpleDateFormat sdf = new SimpleDateFormat(pat1);// 根据 pat1 模板实例化
        // SimpleDateFormat 对象
        String formatDate = sdf.format(date);
        System.out.println("输出当前日期的格式化字符串:" + formatDate);
    }

    // 格式化当前日期时间,模板格式不同输出的当前日期不同
    @Test
    public void testFormatDate2() {
        // 实例化当前时间
        Date date = new Date();
        String pat1 = "yyyy-MMM-dd";
        // 根据pat1模板实例化SimpleDateFormat对象
        SimpleDateFormat sdf = new SimpleDateFormat(pat1);
        String formatDate = sdf.format(date);
        System.out.println("输出当前日期的格式化字符串:" + formatDate);
    }

    // 自定义模板格式化当前日期。
    @Test
    public void testFormatDateByMyStyle() {
        String myStyle = "yyyy年MM月dd号 hh点mm分ss秒SSS毫秒 ";
        SimpleDateFormat sdf = new SimpleDateFormat(myStyle);
        String dateAfterFormat = sdf.format(new Date());
        System.out.println("自己的模板格式化后的当前日期:" + dateAfterFormat);
    }

    @Test
    public void testFormatDateByMyStyle2() {
        // 自定义的模板,只包含模式字符,则可以自定义
        String myStyle = "yyyy---MMdd";
        SimpleDateFormat sdf = new SimpleDateFormat(myStyle);
        String dateAfterFormat = sdf.format(new Date());
        System.out.println("自己的模板格式化后的当前日期:" + dateAfterFormat);
    }

    // 将date对象只抽取出年月日,完了再转换成date对象。
    // 这种方式转换出的date只能是默认格式。
    // 注意:Java中的date直接输出只能是默认格式,如果需要自定义个数,必须将date格式化为指定的字符串才可。
    // 注意:只能通过SimpleDateFormat先将date对象format成固定格式的字符串,再通过SimpleDateFormat对象将格式化后的字符串解析成date对象。
    @Test
    public void testFormatDate() throws ParseException {
        // 自定义的模板,只包含模式字符,则可以自定义
        String myStyle = "yyyyMMdd";
        SimpleDateFormat sdf = new SimpleDateFormat(myStyle);
        String dateAfterFormat = sdf.format(new Date());
        System.out.println("自己的模板格式化后的当前日期字符串形式:" + dateAfterFormat);
        Date date = sdf.parse(dateAfterFormat);
        dateAfterFormat = sdf.format(date);
        System.out.println("自己的模板格式化后的当前日期:" + dateAfterFormat);

        String myStyle1 = "hh:mm:ss";
        sdf = new SimpleDateFormat(myStyle1);
        dateAfterFormat = sdf.format(new Date());
        System.out.println("自己的模板格式化后的当前日期字符串形式:" + dateAfterFormat);
    }
}

运行结果:

当前毫秒数:1637740681414
默认日期:Wed Nov 24 15:58:01 CST 2021
Mon Sep 03 00:00:00 CST 2018
对提取出来的日期对象格式化:2018-09-03

Process finished with exit code 0

输出提取出来的日期对象格式化后的日期时间字符串:2018年10月19号  10点11分30秒234毫秒

Process finished with exit code 0

输出当前日期的格式化字符串:2021-11-24 03:59

Process finished with exit code 0

输出当前日期的格式化字符串:2021-十一月-24

Process finished with exit code 0

自己的模板格式化后的当前日期:2021年11月24号 04点00分10秒672毫秒 

Process finished with exit code 0

自己的模板格式化后的当前日期:2021---1124

Process finished with exit code 0

自己的模板格式化后的当前日期字符串形式:20211124
自己的模板格式化后的当前日期:20211124
自己的模板格式化后的当前日期字符串形式:04:00:40

Process finished with exit code 0

案例2:

package zeh.myjavase.code18classlib.date.util;

import java.text.SimpleDateFormat;
import java.util.Date;

// 日期时间类
public class DateTimeUtil2 {
    // 声明SimpleDateFormat对象
    private SimpleDateFormat sdf = null;

    // 得到完整的日期,格式为:yyyy-MM-dd HH:mm:ss.SSS
    public String getDate() {
        this.sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        return this.sdf.format(new Date());// 按照模板格式化日期
    }

    // 得到完整的日期,格式为:yyyy年MM月dd日HH时mm分ss秒SSS毫秒
    public String getDateComplete() {
        this.sdf = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒SSS毫秒");
        return this.sdf.format(new Date());
    }

    // 得到时间戳,格式为:yyyyMMddHHmmssSSS
    public String getTimeStamp() {
        this.sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        return this.sdf.format(new Date());
    }
}

package zeh.myjavase.code18classlib.date;

import zeh.myjavase.code18classlib.date.util.DateTimeUtil2;

// 取得完整日期-基于SimpleDateFormat类。
// 专门设计一个类,专门用来取得完整日期格式。
public class Demo05StudyDateAndGetDate {
    public static void main(String args[]) {
        DateTimeUtil2 dt2 = new DateTimeUtil2();
        System.out.println("DateTime2取得系统日期:" + dt2.getDate());
        System.out.println("DateTime2取得中文环境下的日期:" + dt2.getDateComplete());
        System.out.println("DateTime2取得时间戳:" + dt2.getTimeStamp());
    }
}

运行如下:

DateTime2取得系统日期:2021-11-24 16:20:56.904
DateTime2取得中文环境下的日期:2021年11月24日16时20分56秒905毫秒
DateTime2取得时间戳:20211124162056906

文档信息

Search

    Table of Contents