实战小技巧:字符串占位替换-JDK版

简介: 接下来我们看一下在我们的日常工作生涯中,经常涉及到的几种占位替换方式

字符串占位替换,相信没有小伙伴是陌生的,这东西可以说是伴随着我们所有的项目工程,编码过程;别不相信,如


  • String.format
  • sql 参数拼接的占位
  • log 日志输出


接下来我们看一下在我们的日常工作生涯中,经常涉及到的几种占位替换方式


1. String.format



这种可以说是最原始最基础的方式了,基本上在最开始学习 java 这门语言的时候就会涉及到,语法也比较简单


举例如下

String.format("hello %s", "一灰灰blog”);
复制代码


使用%来表示占位,后面跟上不同的标识符,用于限定这个占位处的参数类型

这种使用姿势,由 jdk 原生提供支持,下表为不同的转换符对应的说明


转换符 说明 参数实例
%s 字符串替换 "一灰灰"
%c 字符类型 'a'
%b 布尔类型 true/false
%d 整数,十进制 10
%x 整数,十六进制 0x12
%o 整数,八进制 012
%f 浮点 0.12f
%e 指数 2e2
%g 通用浮点型
%h 散列
%% 百分比
%n 换行
%tx 日期与时间类型(x 代表不同的日期与时间转换符


虽然上面表中列出了很多,但实际使用时,%s, %d, %f 这三个就足以应付绝大部分的场景了;使用姿势和上面的实例参不多,第一个参数为字符串模板,后面的可变参数为待替换的值


下面是在实际使用过程中的注意事项


1.1 类型不匹配


上面的表中介绍了不同的转换符,要求的参数类型,如果没有对应上,会怎样

%s,传入非字符串类型

@Test
public void testFormat() {
    System.out.println(String.format("hello %s", 120));
    System.out.println(String.format("hello %s", true));
    System.out.println(String.format("hello %s", new int[]{1,2, 3}));
    System.out.println(String.format("hello %s", Arrays.asList(1, 2, 3)));
    System.out.println(String.format("hello %s", 0x12));
}
复制代码


输出如下

hello 120
hello true
hello [I@3d82c5f3
hello [1, 2, 3]
hello 18
复制代码


也就是说,%s的占位标记,传参如果不是 String 类型,那么实际替换的是 arg.toString() (所以数组输出的是地址,而 list 输出了内容)


%d,传入非整数


与字符串的不一样的是,如果我们定义要求替换的参数类型为整数,那么传参不是整数,就会抛异常

System.out.println(String.format("hello %d", 1.0F));
System.out.println(String.format("hello %d", "10"));
复制代码


上面这两个,一个传入的参数为浮点,一个传入的是字符串,在实际替换的时候,可不会调用Integer.valufOf(String.valueOf(xxx))来强转,而是采用更直接的方式,抛异常


关键的提示信息如下

java.util.IllegalFormatConversionException: d != java.lang.Float
java.util.IllegalFormatConversionException: d != java.lang.String
复制代码


因此在实际使用这种方式进行替换时,推荐选择 %s,毕竟兼容性更好


1.2 参数个数不匹配


我们会注意到,String.format接收的参数是不定长的,那么就可能存在字符串模板中预留的占位与实际传入的参数个数不匹配的场景,那么出现这种场景时,会怎样


参数缺少

System.out.println(String.format("hello %s %s", "yihui"));
复制代码


上面的例子中,模板要求两个,实际只传入一个参数,会直接抛异常MissingFormatArgumentException


java.util.MissingFormatArgumentException: Format specifier '%s'
复制代码


参数过多


System.out.println(String.format("hello %s", "yihuihui", "blog"));
复制代码


执行正常,多余的参数不会被替换


因此,我们在使用String.format进行字符串替换时,请确保传参不要少于实际定义的参数个数;多了还好,少了就会抛异常


2. MessageFormat


上面介绍的 String.format 虽说简单好用,但我们用多之后,自然会遇到,一个参数,需要替换模板中多个占位的场景,针对这种场景,更友好的方式是MessageFormat,这个也是 jdk 原生提供的


我们来简单看一下它的使用姿势

String ans = MessageFormat.format("hello {0}, wechart site {0}{1}", "一灰灰", "blog");
复制代码


使用{数字}来表示占位,其中数字对应的是传参的下标,因此当一个参数需要复用时,使用 MessageFormat 就可以比较简单的实现了,上面就是一个实例,替换之后的字符串为


hello 一灰灰, wechart site 一灰灰blog
复制代码


接下来说一下它使用时的注意事项


2.1 {}成对出现


如果字符串中,只出现一个{,而没有配套的},会抛异常

System.out.println(MessageFormat.format("hello }", 123));
System.out.println(MessageFormat.format("hello { world",  456));
复制代码


注意上面两种 case,上面一个是有}而缺少{,这样是没有问题的;而下面那个则会抛异常


java.lang.IllegalArgumentException: Unmatched braces in the pattern.
复制代码


如果字符串中却是希望输出{,可以使用单引号来处理


System.out.println(MessageFormat.format("hello '{' world",  456));
复制代码


2.2 单引号


上面提到需要转移时,可以用单引号进行处理,在字符串模板的定义中,如果有单引号,需要各位注意


只有一个单引号,会导致后面所有占位都不生效

System.out.println(MessageFormat.format("hello {0}, I'm {1}", "一灰灰", "blog"));
复制代码


上面这个输出结果可能和我们实际希望的不一致

hello 一灰灰, Im {1}
复制代码


要解决上面这个,就是使用两个单引号

System.out.println(MessageFormat.format("hello {0}, I''m {1}", "一灰灰", "blog"));
复制代码


这样输出的就是我们预期的

hello 一灰灰, I'm blog
复制代码


2.3 序号省略


上面的定义中,已经明确要求我们在{}中指定参数的序号,如果模板中没有指定会怎样?


System.out.println(messageFormat.format("hello {}, world", "yihuihui"));
复制代码


直接抛异常

java.lang.IllegalArgumentException: can't parse argument number:
复制代码


3. 小结


本文介绍的实战小技巧属于是 jdk 原生提供的两种实现字符串占位替换的方式,特别注意使用细节,如format的参数类型需要匹配,参数个数不能缺少;MessageFormat的单引号问题等


除了这两个之外,我们日常开发中还会遇到其他的占位替换方式


比如 sql 的?替换,mybatis 中 sql 参数组装使用${paramName},或者 logback 日志输出中的{}来表示占位,spring 的@Value 注解声明的配置注入方式

${name:defaultValue},这些也都属于占位替换的范畴,那么它们又是怎么实现的呢?


且看下文



相关文章
|
安全 Java 编译器
JDK21更新内容:字符串模板
JDK21更新内容:字符串模板
|
4月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
27天前
|
安全 Java 开发者
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战模拟
【11月更文挑战第21天】面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(cross-cutting concerns)与业务逻辑分离,以提高代码的可维护性和可重用性。在Java开发中,AOP的实现离不开动态代理技术,其中JDK动态代理和CGLIB动态代理是两种常用的方式。本文将从背景、历史、功能点、业务场景、底层逻辑等多个维度,深度解析这两种代理方式的区别,并通过Java示例进行模拟和比较。
43 4
|
3月前
|
Oracle Java 关系型数据库
CentOS 7.6操作系统部署JDK实战案例
这篇文章介绍了在CentOS 7.6操作系统上通过多种方式部署JDK的详细步骤,包括使用yum安装openjdk、基于rpm包和二进制包安装Oracle JDK,并提供了配置环境变量的方法。
293 80
|
3月前
|
IDE Java 数据处理
【字符串构建的全新时代】JDK 22字符串模板:让字符串操作如行云流水,代码更流畅!
【9月更文挑战第8天】虽然目前JDK 22的确切内容尚未公布,但我们可以根据Java语言的演进趋势和社区的需求,构想出一种可能在未来版本中引入的字符串模板机制。这种机制有望为Java的字符串操作带来革命性的变化,让代码编写如行云流水般流畅。我们期待Java语言能够不断进化,为开发者们提供更加高效、便捷和强大的编程工具。
|
4月前
|
XML JSON Java
JDK8到JDK26版本升级的新特性问题之在JDK 13中,字符串文本块改进字符串嵌入是如何实现的
JDK8到JDK26版本升级的新特性问题之在JDK 13中,字符串文本块改进字符串嵌入是如何实现的
|
7月前
|
监控 前端开发 安全
JVM工作原理与实战(十四):JDK9及之后的类加载器
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了JDK8及之前的类加载器、JDK9及之后的类加载器等内容。
178 2
|
7月前
|
安全 Java 开发者
jdk1.8 Optional类从入门到实战
Optional 类是 Java 8 引入的一个容器类,用于表示一个值存在或不存在。其在 java.util 包中,主要目的是为了解决 Java 程序中广泛存在的空指针异常(NullPointerException)问题,同时提供了一种更优雅的方式来处理可能为 null 的对象。 在 Java 8 之前,处理 null 值往往依赖于显式的 null 检查,这种方式不仅增加了代码的复杂度,而且容易出错。Optional 类提供了一种更好的解决方案,通过封装可能为 null 的值,强制开发者显式地处理值存在或不存在的情况,从而减少在运行时出现 NullPointerException 的可能性。
52 3
|
Java
java202303java学习笔记第三十五天IO流中不同JDK版本字符串方式4
java202303java学习笔记第三十五天IO流中不同JDK版本字符串方式4
41 0
|
7月前
|
XML SQL 自然语言处理
JDK 21中的字符串模板:提升代码可读性与维护性的新利器
本文将介绍JDK 21中引入的字符串模板特性,它是一种创新的文本生成技术,旨在提高代码的可读性和维护性。字符串模板允许开发者使用简洁的语法来构建复杂的字符串,减少了硬编码和字符串拼接的工作量。本文将详细阐述字符串模板的语法、使用场景以及与传统字符串处理方法的比较,并通过示例代码展示其在实际开发中的应用。