黑马Java基础笔记-7

StringJoiner

import java.util.StringJoiner;

StringJoiner 是 Java 8 引入的工具类,用于构造由分隔符连接的字符串序列,并支持添加前缀和后缀。它能自动处理分隔符插入,避免手动拼接字符串时的边界判断问题(例如最后一个元素后不加分隔符)。

核心功能

方法/构造器作用说明
new StringJoiner(" ")创建一个分隔符为空格、无前缀/后缀的拼接器
new StringJoiner(",", "[", "]")创建分隔符为逗号、前缀为 [、后缀为 ] 的拼接器(例如 [a,b,c]
add(String str)添加一个字符串元素,自动插入分隔符
merge(StringJoiner other)合并另一个 StringJoiner 的内容(保留当前分隔符和前后缀)
toString()生成最终字符串
length()返回长度**(是字符出现的个数,包括前缀后缀和间隔符,并不是add方法添加的个数)**

代码示例

StringJoiner sj = new StringJoiner("-", "【", "】");
sj.add("Java");
sj.add("Python");
sj.add("C++");
System.out.println(sj.toString());  // 输出:【Java-Python-C++】
System.out.println(sj.length());    // 输出:17 而不是3

与传统方法对比

使用 StringBuilder(需手动处理分隔符)
StringBuilder sb = new StringBuilder("【");
String[] arr = {"Java", "Python", "C++"};
for (int i = 0; i < arr.length; i++) {
    sb.append(arr[i]);
    if (i != arr.length - 1) {
        sb.append("-");  // 判断是否为最后一个元素
    }
}
sb.append("】");
System.out.println(sb.toString());
使用 StringJoiner(自动处理分隔符)
StringJoiner sj = new StringJoiner("-", "【", "】");
for (String s : arr) {
    sj.add(s);
}
System.out.println(sj.toString());

关键优势

  • 自动分隔符处理:无需手动判断是否为最后一个元素,代码更简洁且不易出错。

  • 支持前缀/后缀:可一键添加统一的前后缀(如生成 JSON 数组、带括号列表)。

  • 链式调用支持:例如:

    String result = new StringJoiner(",")
                        .add("A").add("B").add("C")
                        .toString();  // "A,B,C"
    
  • 与 Stream API 集成:可用于 Collectors.joining(),简化流操作。

适用场景: 日志拼接、生成 CSV 数据、构建格式化字符串(如 JSON 数组、SQL 的 IN 条件)以及频繁动态拼接字符串。


字符串拼接的底层原理

纯字符串常量

纯字符串常量拼接时(无变量参与),触发编译期优化机制,直接合并为完整字符串常量

public class Test {
    public static void main(String[] args) {
        String s = "a" + "b" + "c";  // 连续字符串拼接
        System.out.println(s);
    }
}

在编译为class文件后:

public class Test {
    public static void main(String[] args) {
        String s = "abc";  // 优化后的等效代码,可以直接复用串池中的"abc"(如果存在的话)
        System.out.println(s);
    }
}

常量加变量

Java8以前

底层调用的是StringBuilderappend()方法来拼接字符串,并通过toString()生成一个String对象(底层是new出来一个String对象):

在这里插入图片描述

// 编译器转换后的等效代码(图像右侧示例)

String s2 = new StringBuilder().append(s1).append("b").toString();

一个加号在堆中会创建两个对象

Java8

JDK8字符串拼接的底层原理_编程语言-CSDN问答

有很多种方式,这个只是默认

先预估要拼接的长度并创建一个数组:

在这里插入图片描述

通过数组来创建字符串,减少创建的对象:

在这里插入图片描述

String s1 = "Hello";
String s2 = "World";
String result = s1 + s2 + "c";

在 JDK 7 及更早版本中

  • s1 + s2 会创建一个临时的 StringBuilder,并将其转换为一个新的 String 对象。
  • 然后再用这个新对象与 "c" 拼接,再次创建一个新的 String 对象。
  • 总共可能涉及多次扩容和对象创建。

在 JDK 7 Update 6+(含 Java 8)中

  • JVM 会预估最终字符串的长度为 s1.length() + s2.length() + "!".length()
  • 创建一个初始容量合适的 StringBuilder,并将所有部分一次性拼接。
  • 最终只生成一个 String 对象。

在Java 8中,对于字符串拼接的底层优化主要体现在String类的+操作符上。在JDK 5及以后版本中,编译器会对字符串字面量(常量)的拼接进行静态优化,直接在编译期间合并成一个字符串常量存储到常量池中,这不会涉及运行时创建额外对象。

而对于非字符串字面量的动态拼接,即在运行时才知道拼接内容的情况,在Java 7及更早版本中,每使用一次+运算符拼接字符串,都会生成一个新的String对象,这是因为String是不可变的,每次拼接都需要创建新的char[]数组来存储结果。

然而,从Java 7 Update 6之后的一个性能改进开始(这项改进后来也包含在所有后续版本中,包括Java 8),JVM实现了一种称为“字符串串联缓存”(String Concatenation Cache)的技术。对于通过StringBuilderStringBuffer完成字符串连接的地方,如果代码看起来像是连续的String变量和字面量的拼接,JVM会自动优化为使用StringBuilder来执行这些操作,并且它会尝试预估最终字符串的长度以减少数组扩容带来的性能损耗。

具体来说,当JVM检测到可能的字符串拼接循环或多次拼接时,它会创建一个内部的字符数组(char[]),并根据需要逐步添加字符串的内容,而不是每次都创建新的String对象。这个内部的字符数组就是用来构建最终拼接结果的缓冲区。

因此,尽管没有明确的方法可以直接查看JVM是否以及如何创建了内部的字符数组,但可以确认的是,JVM在处理非编译期优化的字符串拼接时,确实采用了更为高效的方式,利用类似于StringBuilder的机制,并预估和分配足够的字符数组空间来避免频繁的内存重分配和复制操作。

Java9及以后(待补充)


集合

ArrayList 成员方法

操作方法名说明
boolean add(E e)添加元素,返回值表示是否添加成功
boolean remove(E e)删除指定元素,返回值表示是否删除成功
E remove(int index)删除指定索引位置的元素
E set(int index, E e)修改指定索引位置的元素,返回修改前的元素
E get(int index)获取指定索引位置的元素
int size()返回集合长度,即集合中元素的个数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值