Java: java.text.Format体系总结

本文介绍了Java中日期和数字格式化的实现方法,包括DateFormat、MessageFormat和NumberFormat的使用技巧,及其子类如SimpleDateFormat、DecimalFormat和ChoiceFormat的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://jianzong2000.iteye.com/blog/406304


1.1. Format的方法 
java.text.Format做为一个抽象类,有二个抽象方法, 
format(Object obj, StringBuffer toAppendTo, FieldPosition pos):格式化一个对象,并将得到的文本追加到给定的字符缓冲区。是将obj格式化为字符串,并加入到toAppendTo中。 
parseObject(String source, ParsePosition pos): 分析字符串文本,生成一个对象。是format方法的逆向方法,将String转化为Object。 
另外的format和parseObject这两个方法的重载。 
方法formatToCharacterIterator(Object obj)并非抽象方法,api上要求子类必须实现这个方法。 

1.2. Format的子类 
Java 2 平台为格式化日期、消息和数字分别提供了三个特殊的 Format 的子类:DateFormat(抽象类)、MessageFormat 和 NumberFormat(抽象类)。 
    ——>DateFormat   ——>SimpleDateFormat 
Format  ——>MessageFormat 
——>NumberFormat——>ChoiceFormat 
——> DecimalFormat用于格式化十进制数字 

1.3. DateFormat的用法 
DateFormat 是日期/时间格式化子类的抽象类, 有一些static的get***Instance()方法来获得实例。通过设置结果的长度和地区,来获得日期,时间等的格式formatter。不太常用。 
一般会使用SimpleDateFormat子类,new SimpleDateFormat("yyyy-MM-dd")或new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),来获得常用的时间格式。DateFormat 的get***Instance()方法一般也是获得SimpleDateFormat。 
看DateFormat的源代码有个疑问,如果继承了DateFormat类,那DateFormat. get***Instance()的方法还是返回SimpleDateFormat? DateFormat.get是私有的,也不能覆盖。 
DateFormat类中还有一些static的字段,如WEEK_OF_MONTH_FIELD, WEEK_OF_YEAR_FIELD。api上说在FieldPosition中使用,用于对齐。 
java.util.Calendar也是日期操作相关的类,实现类为GregorianCalendar。主要对日期进行操作。注意add方法和roll方法的区别,roll方法不更改更大的字段。还有一些静态的变量DAY_OF_MONTH,DAY_OF_WEEK等,在get/set/add/roll方法中使用。 

1.4. MessageFormat的用法 
和SimpleDateFormat一样,也需要传入一个pattern。如 
String result = MessageFormat.format( 
     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", 
     7, new Date(), “ a message ”); 
其中 
{1,time}中1是指第几个参数,time是指格式化的类型。根据api进行设置,是调用NumberFormat和DateFormat进行格式化的。 
还可以调用parse方法将字符串转化为Obejct。 

1.5. NumberFormat的用法 
1.5.1. NumberFormat的介绍 
NumberFormat 是所有数字格式的抽象基类。类结构与DateFormat类似。主要也是通过get***Instance方法获得实现类DecimalFormat。 
比较常用的方法有: 
setParseIntegerOnly:只影响分析。设为true,则忽略小数点以后的位置。 
setDecimalSeparatorAlwaysShown:只影响格式化,且只影响小数点后没有数字的情况?设置分组符号是否显示。例如1,234中的,号是否显示。 
setGroupingUsed:是否分组。如果此格式中使用了组,则返回 true。例如,在英国语言环境中,如果设置了组,则数 1234567 可能被格式化为 "1,234,567"。 
还可以设置小数/整数部分的最大/小位数。 
关于parse方法中的ParsePosition 和 format方法中的FieldPosition待研究。 

1.5.2. 子类DecimalFormat 
DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字。在DecimalFormat中传入pattern,可以自定义格式化类型。舍入方式是half-even(四舍五入)。 
DecimalFormat 模式包含正数和负数子模式,例如 "#,##0.00;-#,##0.00"。;后面的代表负数模式。单独的 "0.00" 等效于 "0.00;-0.00"。如果存在显式的负数子模式,则它仅指定负数前缀和后缀; 
0:代表是数字;如果不存在则显示为0; 
#:代表是数字; 
,:分组分隔符;没有则不分组 

1.5.3. 子类ChoiceFormat 
ChoiceFormat通常用于在 MessageFormat 中处理复数。创建 ChoiceFormat 时,可以指定一个 format 数组和一个 limit 数组。这些数组的长度必须相同。 
如api中用于转换星期的例子 
double[] limits = {1,2,3,4,5,6,7}; 
String[] monthNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}; 
ChoiceFormat form = new ChoiceFormat(limits, monthNames); 
ParsePosition status = new ParsePosition(0); 
for (double i = 0.0; i <= 8.0; ++i) { 
     status.setIndex(0); 
     System.out.println(i + " -> " + form.format(i) + " -> " 
                              + form.parse(form.format(i),status)); 

form.format(i)根据limits的数字转换为星期几的名称。limits中的数字必须按升序排列,如果提供的数字不在limits中,则选择使用第一个或最后一个索引。 
form.parse(form.format(i),status),则根据Name转换为limits中的值。 

1.5.4. ChoiceFormat的例子 
下面是ChoiceFormat的api中一个较复杂的带模式格式的例子, 和MessageFormat一起使用: 
//生成ChoiceFormat 
double[] filelimits = {0,1,2}; 
String[] filepart = {"are no files","is one file","are {2} files"};//这里的2是指从testArgs中取第二个元素的值 
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); 

//定义Format数组testFormats,分别为ChoiceFormat,null, NumberFormat 
//ChoiceFormat用于{0}, null用于{1}, NumberFormat用于{2} 
Format[] testFormats = {fileform, null, NumberFormat.getInstance()}; 

//将MessageFormat的formats设为testFormats 
//testFormats中的格式顺序对应于模式字符串中的格式元素的顺序 
//最好使用setFormatsByArgumentIndex方法,而不是使用setFormats 
MessageFormat pattform = new MessageFormat("There {0} on {1}"); 
pattform.setFormats(testFormats); 

//进行fomat 
Object[] testArgs = {null, "ADisk", null}; 
for (int i = 0; i < 4; ++i) { 
     testArgs[0] = new Integer(i); 
     testArgs[2] = testArgs[0]; 
//此时的testArgs值为{0, "ADisk",0} 
//根据MessageFormat的定义,对testArgr元素进行处理 
     System.out.println(pattform.format(testArgs)); 


1.5.5. ChoiceFormat的pattern构造方法 
ChoiceFormat还有另外一个构造方法,传入pattern。 
为 ChoiceFormat 对象指定一个模式是相当直接的。例如: 
ChoiceFormat fmt = new ChoiceFormat( 
      "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2."); 
其中数字#是按照大小顺序排列的, formate方法中传入参数x,如果x在0,1之间,则按照0处理。 

1.5.6. 其它的数字格式化 
另外在对数字进行格式化时,也可以考虑使用java.math.BigDecimal。 
如setScale(int newScale,int roundingMode):newScale指精确度,即保留几位小数。roundingMode指舍入模式,常用的是四舍五入。DecimalFormat貌似只能使用四舍五入,如果使用别的舍入方式,就要使用BigDecimal了。 
java.lang.Integer中的几个转换进制的方法也比较实用 
toBinaryString(int i): 以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。 
toHexString(int i): 以十六进制的无符号整数形式返回一个整数参数的字符串表示形式 
toOctalString(int i) :以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。 

<think>首先,用户的问题是中文的:"java 批量 导入excel 报错 com.alibaba.excel.exception.ExcelDataConvertException: Convert data com.alibaba.excel.metadata.data.ReadCellData@74224c6c to class java.lang.String error 和 Caused by: java.lang.IllegalArgumentException: Cannot format given Object as a Number at java.text.DecimalFormat.format(DecimalFormat.java:507) at com.alibaba.excel.metadata.format.ExcelGeneralNumberFormat.format(ExcelGeneralNumberFormat.java:58)" 这是一个关于Java中使用EasyExcel(或类似库)导入Excel时遇到的错误。主要错误是ExcelDataConvertException,表示将数据转换为String时出错,根本原因是IllegalArgumentException,说无法将对象格式化为数字。 我需要用中文回答问题,因为用户指定了“请使用中文回答问题”。 关键点是: - 错误发生在数据转换时,具体是尝试将某个对象格式化为数字时失败。 - 堆栈跟踪指向DecimalFormat.format和ExcelGeneralNumberFormat.format。 可能的原因: 1. Excel单元格中的数据类型与Java实体类中的字段类型不匹配。例如,单元格中是数字,但Java字段是String。 2. 格式问题:单元格可能包含特殊字符或格式,导致解析失败。 3. EasyExcel配置问题:可能需要自定义转换器来处理特定数据类型。 解决方案思路: - 检查Excel文件:确保单元格数据正确。 - 检查Java实体类:字段类型是否匹配Excel数据类型。如果字段是String,但单元格是数字,EasyExcel可能会尝试转换,但失败。 - 使用自定义转换器:实现Converter接口来处理特定类型的数据转换。 - 调试:打印出有问题的单元格数据,看看实际值是什么。 在回答中,我需要提供具体的解决建议。 现在,回答后,必须提出3-5个相关问题。问题必须以“§§相关问题§§”开头,第一行必须是这个字符串,然后列出问题,用数字点号,如1. ··· 2. ··· 3. ··· 相关问题应该基于用户的问题和我的回答。例如: 1. 如何实现自定义转换器来解决数据类型不匹配问题? 2. 在EasyExcel中,如何处理Excel中的数字格式? 3. 为什么会出现IllegalArgumentException: Cannot format given Object as a Number? 4. 如何调试EasyExcel导入过程中的数据转换问题? 5. 批量导入Excel时,如何优化性能以避免类似错误? 确保问题数量在3到5个。 最后,确保整个响应符合格式要求:先回答问题,然后以“§§相关问题§§”开头,列出问题。 结构: 1. 解释错误原因。 2. 提供解决方案步骤。 3. 建议预防措施。 4. 然后,输出相关问题。</think>### 问题分析 在 Java 中使用 EasyExcel 库批量导入 Excel 文件时,报错 `com.alibaba.excel.exception.ExcelDataConvertException` 和 `Caused by: java.lang.IllegalArgumentException: Cannot format given Object as a Number`,主要原因是数据转换失败。具体来说: - **根本原因**:Excel 单元格中的数据类型(如数字或特殊格式)与 Java 实体类中定义的字段类型(如 `String`)不匹配。EasyExcel 在尝试将单元格数据(如数字)强制转换为 `String` 时,触发了数字格式化异常。 - **常见场景**: - Excel 单元格包含数字(如 `123.45`),但 Java 实体类字段是 `String` 类型,导致 `DecimalFormat` 在内部转换时失败。 - Excel 数据包含特殊字符(如货币符号 `$` 或千位分隔符 `,`),导致解析错误。 - 批量导入时,部分数据行格式异常,引发连锁错误。 ### 解决方案 以下是逐步解决步骤(以 EasyExcel 为例): 1. **检查 Excel 数据和 Java 实体类映射**: - 确保实体类字段类型与 Excel 单元格数据类型一致。例如: - 如果 Excel 单元格是数字,实体类字段应使用 `Double`、`Integer` 等数值类型,而非 `String`。 - 如果字段必须是 `String`,使用 `@ExcelProperty` 注解指定转换器。 ```java public class YourEntity { @ExcelProperty("列名") // 确保列名匹配 private Double numberField; // 改为数值类型 } ``` 2. **添加自定义转换器**: - 实现 `Converter<T>` 接口,处理数字到字符串的转换。例如: ```java public class CustomStringConverter implements Converter<String> { @Override public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { // 直接返回字符串形式,避免格式化错误 return cellData.getStringValue(); // 或 cellData.getNumberValue().toString() 处理数字 } } ``` - 在实体类中使用: ```java public class YourEntity { @ExcelProperty(value = "列名", converter = CustomStringConverter.class) private String stringField; // 现在支持数字转换 } ``` 3. **调试和验证数据**: - 在读取时捕获异常并打印问题单元格: ```java ReadListener<YourEntity> listener = new ReadListener<>() { @Override public void onException(Exception exception, AnalysisContext context) { // 打印出错行和列 System.out.println("Error at row: " + context.readRowHolder().getRowIndex()); } }; EasyExcel.read(file, YourEntity.class, listener).sheet().doRead(); ``` - 检查 Excel 文件:用工具(如 Microsoft Excel)打开,确保无隐藏字符或错误格式。 4. **处理批量导入优化**: - 使用 `@ExcelIgnoreUnannotated` 忽略未注解字段,减少错误。 - 设置读取模式:`ExcelReaderBuilder.ignoreEmptyRow(true)` 跳过空行。 - 更新 EasyExcel 版本:确保使用最新版(如 3.x+),避免已知 bug。 ### 预防措施 - 在导入前预处理 Excel:使用 Apache POI 检查数据类型。 - 添加全局异常处理:在 Spring Boot 中,用 `@ControllerAdvice` 捕获 `ExcelDataConvertException`。 - 测试:使用单元测试模拟不同数据类型(如数字、文本、日期)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值