热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:拼接字符串新姿势—StringJoiner

篇首语:本文由编程笔记#小编为大家整理,主要介绍了拼接字符串新姿势—StringJoiner相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了拼接字符串新姿势—StringJoiner相关的知识,希望对你有一定的参考价值。






前言

你知道使用原生 JDK 拼接字符串有多少种玩法吗?我们能想到的大概就是StringBuilder、StringBuffer、 String.concat、还有用 + 拼接。还有其他的吗?接下来就来讲讲 Java 8 里面新增了一个拼接字符串的类 ,叫 StringJoiner 的用法。


概述

StringJoiner 是 java.util 包中的一个类,用于构造一个由分隔符分隔的字符串,并且可以从提供的前缀字符串开头,以提供的后缀字符串结尾。虽然这些功能,我们可以使用 StringBuilder 或者 StringBuffer 来实现的, 但是 StringJoiner 提供的方法更简单,而且也不需要写大量的代码就能成。


构造函数

StringJoiner 一共有 2 个构造函数。 构造函数很简单,就是对 分隔符,前缀和后缀字符串的初始化。

public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");//默认前缀和后缀为"",重载调用
}
public StringJoiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
//间隔符,前缀和后缀判断是否为null,null将抛出异常
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
//成员变量赋值
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
//空值被设置为只有前后缀
this.emptyValue = this.prefix + this.suffix;
}

用法

StringJoiner 的用法其实很简单,来,我们看一下 StringJoiner 字符串拼接的用法。

public class StringJoinerTest {
public static void main(String[] args) {
StringJoiner sj = new StringJoiner("hello");
sj.add("Java 8 ");
sj.add("Java 11");
System.out.println(sj.toString());
StringJoiner sj1 = new StringJoiner(":","[","]");
sj1.add("Java8").add("Java11").add("Java15");
System.out.println(sj1.toString());
}
}

输出结果:

Java 8 helloJava 11
[Java8:Java11:Java15]

注意:


  1. 当我们使用StringJoiner(CharSequence delimiter)初始化一个StringJoiner的时候,这个delimiter其实是分隔符,并不是字符串的初始值。
  2. StringJoiner(CharSequence delimiter,CharSequence prefix,CharSequence suffix)的第二个和第三个参数分别是拼接后的字符串的前缀和后缀。

源码分析



JDK8中源码


public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
@Override
public String toString() {
if (value == null) {
return emptyValue;
} else {
if (suffix.equals("")) {
return value.toString();
} else {
int initialLength = value.length();
String result = value.append(suffix).toString();
value.setLength(initialLength);
return result;
}
}
}
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
public StringJoiner merge(StringJoiner other) {
Objects.requireNonNull(other);
if (other.value != null) {
final int length = other.value.length();
StringBuilder builder = prepareBuilder();
builder.append(other.value, other.prefix.length(), length);
}
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
public int length() {
return (value != null ? value.length() + suffix.length() :
emptyValue.length());
}


JDK11中源码


public final class StringJoiner {
private String[] elts;
@Override
public String toString() {
final String[] elts = this.elts;
if (elts == null && emptyValue != null) {
return emptyValue;
}
final int size = this.size;
final int addLen = prefix.length() + suffix.length();
if (addLen == 0) {
compactElts();
return size == 0 ? "" : elts[0];
}
final String delimiter = this.delimiter;
final char[] chars = new char[len + addLen];
int k = getChars(prefix, chars, 0);
if (size > 0) {
k += getChars(elts[0], chars, k);
for (int i = 1; i k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
}
}
k += getChars(suffix, chars, k);
return new String(chars);
}
public StringJoiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
elts = new String[8];
} else {
if (size == elts.length)
elts = Arrays.copyOf(elts, 2 * size);
len += delimiter.length();
}
len += elt.length();
elts[size++] = elt;
return this;
}
}

比较一下JDK8和JDK11中StringJoiner的源码add 方法的实现:


  1. JDK8中StringJoiner 是通过 StringBuilder 来实现的;

  2. JDK11中StringJoiner 就是把待拼接的字符串,放到一个字符串数组里面,toString() 方法的时候,才是真正做字符串拼接的过程。

那么问题来了,既然 JDK 8 的时候,已经使用了StringBuilder 来实现,JDK11为什么还要改成 String[] 来缓存所有的待拼接的字符串。这个就要涉及到JVM底层的优化了。

既然已经有了StringBuilder,为什么还要造一个StringJoiner,它的优势到底在哪里,那我们再来找找原因,我们可以看到代码的注释块中,标记了 Collectors#joining 。

我们看看 Collectors#joining 究竟做了什么呢?

public static Collector joining() {
return new CollectorImpl(
StringBuilder::new, StringBuilder::append,
(r1, r2) -> { r1.append(r2); return r1; },
StringBuilder::toString, CH_NOID);
}
public static Collector joining(CharSequence delimiter) {
return joining(delimiter, "", "");
}
public static Collector joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
return new CollectorImpl<>(
() -> new StringJoiner(delimiter, prefix, suffix),
StringJoiner::add, StringJoiner::merge,
StringJoiner::toString, CH_NOID);
}

原来 Java 8 中Stream 是借助了 StringJoiner 来实现的。 这个时候&#xff0c;我们可能会想&#xff0c;为什么不使用 StringBuilder 来实现呢&#xff1f; 我们可以从示例里看出&#xff0c;如果 StringBuilder 来构造拼接的话&#xff0c;在没有前后缀的情况下&#xff0c;应该还是简单的&#xff0c;但是一旦到需要其他前后缀的拼接&#xff0c;那这个就变得很复杂啦。

所以 StringJoiner 在 Java 8 的地位是 StringBuilder 所不能代替的。


总结

本文介绍了 Java 8 开始提供的字符串拼接类 StringJoiner。 JDK 8 中 StringJoiner 是通过 StringBuilder 实现的&#xff0c; 所以它的性能和StringBuilder 差不多&#xff0c;它也是非线程安全的。JDK 11 中已经对其进行了优化&#xff0c;通过 String[] 来代理 StringBuilder 。

在日常的开发过程中&#xff0c;我们怎么选择字符串拼接类呢&#xff1f;


  1. 简单的字符串拼接&#xff0c;直接使用 &#43; 即可。
  2. 在 for 循环之类的场景下需要字符串拼接&#xff0c;可以优先考虑使用 StringBuilder 。
  3. 在使用 Java Stream 和 lambda 的场景下需要字符串拼接&#xff0c;可以优先考虑使用 StringJoiner。

作为阅读福利我也整理了一些Java学习笔记&#43;面试真题&#xff0c;现在免费分享给阅读到本篇文章的Java程序员朋友们&#xff0c;需要的点击下面链接领取&#xff01;&#xff01;

最全学习笔记大厂真题&#43;微服务&#43;MySQL&#43;分布式&#43;SSM框架&#43;Java&#43;Redis&#43;数据结构与算法&#43;网络&#43;Linux&#43;Spring全家桶&#43;JVM&#43;高并发&#43;各大学习思维脑图&#43;面试集合
在这里插入图片描述
在这里插入图片描述






推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 本文总结和分析了JDK核心源码(2)中lang包下的基础知识,包括常用的对象类型包和异常类型包。在对象类型包中,介绍了Object类、String类、StringBuilder类、StringBuffer类和基本元素的包装类。在异常类型包中,介绍了Throwable类、Error类型和Exception类型。这些基础知识对于理解和使用JDK核心源码具有重要意义。 ... [详细]
  • 本文整理了Java中org.apache.hadoop.hive.ql.plan.ExprNodeColumnDesc.getTypeInfo()方法的一些代码示例,展 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • java drools5_Java Drools5.1 规则流基础【示例】(中)
    五、规则文件及规则流EduInfoRule.drl:packagemyrules;importsample.Employ;ruleBachelorruleflow-group ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 花瓣|目标值_Compose 动画边学边做夏日彩虹
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Compose动画边学边做-夏日彩虹相关的知识,希望对你有一定的参考价值。引言Comp ... [详细]
  • 颜色迁移(reinhard VS welsh)
    不要谈什么天分,运气,你需要的是一个截稿日,以及一个不交稿就能打爆你狗头的人,然后你就会被自己的才华吓到。------ ... [详细]
author-avatar
书友62423539
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有