java.text.MessageFormat 专题

简介: java.text.MessageFormat类MessageFormat提供一种语言无关的方式来组装消息,它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式,在其中你可以用占位符来表示变化的部分: import java.

 

java.text.MessageFormat类
MessageFormat提供一种语言无关的方式来组装消息,它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分。你可以为MessageFormat定义一个模式,在其中你可以用占位符来表示变化的部分:

import java.text.MessageFormat;
import java.util.Date;

public class MessageFormatTest {
    public static void main(String[] args) {
        Object[] arguments = {
                7,
                new Date(System.currentTimeMillis()),
                "a disturbance in the Force"
        };
        String result = MessageFormat.format(
                "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
                arguments);
        System.out.println(result);
        //output:
        // At 14:08:27 on 2017-7-7, there was a disturbance in the Force on planet 7.
    }
}

占位符的格式为{ ArgumentIndex , FormatType , FormatStyle },详细说明可以参考MessageFormat的API说明文档。这里我们定义了两个占位符,其中的数字对应于传入的参数数组中的索引,{0}占位符被第一个参数替换,{1}占位符被第二个参数替换,依此类推。
最多可以设置10个占位符,而且每个占位符可以重复出现多次,而且格式可以不同,比如{1,date}和{1,time},{1,number,#.##}。而通过将这些模式定义放到不同的资源文件中,就能够根据不同的locale设置,得到不同的模式定义,并用参数动态替换占位符。
步骤:
1、找出可变的部分,并据此定义模式,将模式放入不同的资源文件中。
2、创建MessageFormat对象,并设置其locale属性。
MessageFormat formatter = new MessageFormat("");
formatter.setLocale(currentLocale);
3、从资源包中得到模式定义,以及设置参数。
messages = ResourceBundle.getBundle(
"i18n.resource.MessagesBundle",currentLocale);
Object[] arguments= {new Long(3), "MyDisk"};;
4、利用模式定义和参数进行格式化。
String result = MessageFormat.format(messages.getString(key), arguments);

http://blog.csdn.net/turkeyzhou/article/details/4487917

注意:
参数为Number类型或Date类型时,会被格式化。数字会转换成科学计数法,譬如 123456,会format成 123,456
java.text.MessageFormat#subformat

    /**
     * Internal routine used by format. If <code>characterIterators</code> is
     * non-null, AttributedCharacterIterator will be created from the
     * subformats as necessary. If <code>characterIterators</code> is null
     * and <code>fp</code> is non-null and identifies
     * <code>Field.MESSAGE_ARGUMENT</code>, the location of
     * the first replaced argument will be set in it.
     *
     * @exception IllegalArgumentException if an argument in the
     *            <code>arguments</code> array is not of the type
     *            expected by the format element(s) that use it.
     */
    private StringBuffer subformat(Object[] arguments, StringBuffer result,
                                   FieldPosition fp, List<AttributedCharacterIterator> characterIterators) {
        // note: this implementation assumes a fast substring & index.
        // if this is not true, would be better to append chars one by one.
        int lastOffset = 0;
        int last = result.length();
        for (int i = 0; i <= maxOffset; ++i) {
            result.append(pattern.substring(lastOffset, offsets[i]));
            lastOffset = offsets[i];
            int argumentNumber = argumentNumbers[i];
            if (arguments == null || argumentNumber >= arguments.length) {
                result.append('{').append(argumentNumber).append('}');
                continue;
            }
            // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
            if (false) { // if (argRecursion == 3){
                // prevent loop!!!
                result.append('\uFFFD');
            } else {
                Object obj = arguments[argumentNumber];
                String arg = null;
                Format subFormatter = null;
                if (obj == null) {
                    arg = "null";
                } else if (formats[i] != null) {
                    subFormatter = formats[i];
                    if (subFormatter instanceof ChoiceFormat) {
                        arg = formats[i].format(obj);
                        if (arg.indexOf('{') >= 0) {
                            subFormatter = new MessageFormat(arg, locale);
                            obj = arguments;
                            arg = null;
                        }
                    }
                } else if (obj instanceof Number) {
                    // format number if can
                    subFormatter = NumberFormat.getInstance(locale);
                } else if (obj instanceof Date) {
                    // format a Date if can
                    subFormatter = DateFormat.getDateTimeInstance(
                             DateFormat.SHORT, DateFormat.SHORT, locale);//fix
                } else if (obj instanceof String) {
                    arg = (String) obj;

                } else {
                    arg = obj.toString();
                    if (arg == null) arg = "null";
                }

                // At this point we are in two states, either subFormatter
                // is non-null indicating we should format obj using it,
                // or arg is non-null and we should use it as the value.

                if (characterIterators != null) {
                    // If characterIterators is non-null, it indicates we need
                    // to get the CharacterIterator from the child formatter.
                    if (last != result.length()) {
                        characterIterators.add(
                            createAttributedCharacterIterator(result.substring
                                                              (last)));
                        last = result.length();
                    }
                    if (subFormatter != null) {
                        AttributedCharacterIterator subIterator =
                                   subFormatter.formatToCharacterIterator(obj);

                        append(result, subIterator);
                        if (last != result.length()) {
                            characterIterators.add(
                                         createAttributedCharacterIterator(
                                         subIterator, Field.ARGUMENT,
                                         Integer.valueOf(argumentNumber)));
                            last = result.length();
                        }
                        arg = null;
                    }
                    if (arg != null && arg.length() > 0) {
                        result.append(arg);
                        characterIterators.add(
                                 createAttributedCharacterIterator(
                                 arg, Field.ARGUMENT,
                                 Integer.valueOf(argumentNumber)));
                        last = result.length();
                    }
                }
                else {
                    if (subFormatter != null) {
                        arg = subFormatter.format(obj);
                    }
                    last = result.length();
                    result.append(arg);
                    if (i == 0 && fp != null && Field.ARGUMENT.equals(
                                  fp.getFieldAttribute())) {
                        fp.setBeginIndex(last);
                        fp.setEndIndex(result.length());
                    }
                    last = result.length();
                }
            }
        }
        result.append(pattern.substring(lastOffset, pattern.length()));
        if (characterIterators != null && last != result.length()) {
            characterIterators.add(createAttributedCharacterIterator(
                                   result.substring(last)));
        }
        return result;
    }

 


Java里从来少不了字符串拼接的活,Java程序员也肯定用到过StringBuffer,StringBuilder,以及被编译器优化掉的+=。但这些都和下文要谈的无关。

直接使用"+"拼接比较多的字符串,变量一多,可读性就下降,出错的几率就增加,并且难以维护。
需要拼接的变更比较多时,可以使用MessageFormat.format。
示例:

String[] tdArr=...; 
String result=MessageFormat.format("<tr bgcolor='#cef'><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>", tdArr);

 

这段代码将把数组tdArr中的四个元素分别插入到{0},{1},{2},{3}的位置。

你看看,是不是这样形式和内容有效的分开了。容易想象,当元素增多时,这种方式优势很明显。
一件事有很多手段来达成,知道那种手段更好,是你经验的体现和专业化的特征。

 

使用下标来决定拼接的位置,第一个参数的下标为0,pattern中下标的位置是不要求是顺序的

    public static void main(String[] args) {
        String longitude = "1.0";
        String latitude = "2.0";
        String result = "result";
        String geoCode = "geoCode";

        String format1 = MessageFormat.format("longitude:{0},latitude:{1}, body:{2},reGeoCode:{3}", longitude, latitude, result, geoCode);
        System.out.println(format1);
        String format2 = MessageFormat.format("longitude:{3},latitude:{2}, body:{1},reGeoCode:{0}", longitude, latitude, result, geoCode);
        System.out.println(format2);

        String format3 = MessageFormat.format("longitude:{2},latitude:{3}, body:{0},reGeoCode:{1}", longitude, latitude, result, geoCode);
        System.out.println(format3);

    }

输出:

longitude:1.0,latitude:2.0, body:result,reGeoCode:geoCode
longitude:geoCode,latitude:result, body:2.0,reGeoCode:1.0
longitude:result,latitude:geoCode, body:1.0,reGeoCode:2.0

 

 

java.text.MessageFormat格式化字符串时的小技巧

    public static void main(String[] args) throws InterruptedException {
        MessageFormat form = new MessageFormat(
                "{2,date,yyyy-MM-dd HH:mm:ss.SSS} The disk \"{1}\" contains {0,number,#.##} file(s).{3}");
        int fileCount = 1273273237;
        String diskName = "MyDisk";
        Object[] testArgs = {new Long(fileCount), diskName, new Date(),new Date()};
        System.out.println(form.format(testArgs));
    }

 

执行结果:

2016-05-26 13:41:59.162 The disk "MyDisk" contains 1273273237 file(s).16-5-26 下午1:41

 

如果缺少ArgumentIndex 则会报错:

java.lang.IllegalArgumentException: can't parse argument number: 
        at java.text.MessageFormat.makeFormat(MessageFormat.java:1429)
        at java.text.MessageFormat.applyPattern(MessageFormat.java:479)
        at java.text.MessageFormat.<init>(MessageFormat.java:362)
        at java.text.MessageFormat.format(MessageFormat.java:840)

 



 

 

相关文章
|
自然语言处理 安全 Java
java中如何实现多语言切换
java中如何实现多语言切换
669 2
|
消息中间件 程序员 调度
简单高效!本地消息表助你轻松实现分布式事务
本文由小米分享,介绍如何使用本地消息表解决分布式事务问题。分布式事务在微服务架构中变得复杂,本地消息表提供了一种简单高效的方法。它通过在同一事务中处理业务操作和消息记录,然后异步发送消息,确保数据一致性。文章详细阐述了本地消息表的原理、实现步骤、优势及不足,强调了其实现的简单性、高性能和高可靠性,但也指出其潜在的开发复杂度和延迟性问题。
1466 9
|
自然语言处理 Java API
如何在Java中实现多语言国际化支持
如何在Java中实现多语言国际化支持
|
11月前
|
Web App开发 Linux iOS开发
Chrome浏览器如何导出所有书签并导入书签
【11月更文挑战第4天】本文介绍了如何在 Chrome 浏览器中导出和导入书签。导出时,打开书签管理器,点击“整理”按钮选择“导出书签”,保存为 HTML 文件。导入时,同样打开书签管理器,点击“整理”按钮选择“导入书签”,选择之前导出的 HTML 文件即可。其他主流浏览器也支持导入这种格式的书签文件。
8698 2
|
算法 NoSQL 关系型数据库
九种分布式ID解决方案
在复杂的分布式系统中,往往需要对大量的数据进行唯一标识,比如在对一个订单表进行了分库分表操作,这时候数据库的自增ID显然不能作为某个订单的唯一标识。除此之外还有其他分布式场景对分布式ID的一些要求:
1266 0
|
SQL 人工智能 Java
mybatis-plus配置sql拦截器实现完整sql打印
_shigen_ 博主分享了如何在MyBatis-Plus中打印完整SQL,包括更新和查询操作。默认日志打印的SQL用?代替参数,但通过自定义`SqlInterceptor`可以显示详细信息。代码示例展示了拦截器如何替换?以显示实际参数,并计算执行时间。配置中添加拦截器以启用此功能。文章提到了分页查询时的限制,以及对AI在编程辅助方面的思考。
2000 5
mybatis-plus配置sql拦截器实现完整sql打印
|
存储 缓存 Java
Java并发基础:DelayQueue全面解析!
DelayQueue类专为处理延迟任务设计,它允许开发者将任务与指定的延迟时间关联,并在任务到期时自动处理,从而避免了不必要的轮询和资源浪费,此外,DelayQueue内部基于优先队列实现,确保最先到期的任务总是优先被处理,使得任务调度更为高效和精准。
420 1
Java并发基础:DelayQueue全面解析!
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
【4月更文挑战第6天】Java并发编程中,线程池通过重用线程降低性能开销,控制并发级别。关键在于理解线程池工作原理:核心线程数、最大线程数、队列和拒绝策略。优化技巧包括合理设置线程池大小、选择合适队列、避免过度使用、自定义拒绝策略和正确关闭线程池。I/O密集型应用案例:大核心线程数、使用 `CachedThreadPool`、`LinkedBlockingQueue` 和定制拒绝策略。正确配置和管理线程池对提升应用性能至关重要。
659 3
|
存储 移动开发 前端开发
通过刷题HTML遇到的问题
这篇文章总结了HTML和CSS的一些知识点,包括选择器权重、HTML5新增属性和元素、CSS样式声明、超文本定义、元素可见性、Canvas与SVG区别、可继承属性、HTML5语义化标签、固定定位技术、本地存储技术、加粗标签、鼠标悬停事件、DHTML动态样式、jQuery滑动效果、超链接状态、iframe使用场景、置换元素、视频/音频事件以及jQuery透明度渐变方法。