Bootstrap

Java基础语法——字符串(String/StringBuilder/Stringjoiner)


String


Java的String类是不可变的,意味着一旦创建,其值就不能被改变。String类提供了丰富的API来操作字符串。

以下是一些常用的方法:

构造方法:

有以下几种常见的:

public class stringlearn {
    public static void main(String[] args) {
        String str1 = "Hello World";
        String str2 = new String(str1);
        String str3 = new String();

        char[] chararray = {'a', 'b', 'c', 'd', 'e'};
        String str4 = new String(chararray);
        String str5 = new String(chararray,0,2);

        byte[] bytearray = new byte[] {97,98,99,100,101,102,103};
        String str6 = new String(bytearray);

        System.out.println(str1);//Hello World
        System.out.println(str2);//Hello World
        System.out.println(str3);//
        System.out.println(str4);//abcde
        System.out.println(str5);//ab
        System.out.println(str6);//abcdefg
    }
}

Java13引入了引入的文本块的语法。

在文本块中,您可以跨多行定义字符串,而不需要使用\n+来拼接字符串。这样可以提高代码的可读性。

String str = """
                sfsdf
                sfdsd
                dsf
                dsf
                """;
System.out.println(str)

//输出的结果是
sfsdf
sfdsd
dsf
dsf

//

获取字符串长度:

此处str为String的变量名

int length = str.length();

字符访问

char firstchar = str.charAt(0);

// 获取指定位置的字符

子字符串

String Str = str.substring(startIndex);

从startIndex开始截取到字符串末尾

String Str = str.substring(startIndex, endIndex);

截取从startIndex到endIndex(不包括endIndex)的子串

startIndex和endIndex是要截取的位置(下标)

比较字符串

一、比较内容是否相等

boolean isEqual = str.equals(anotherStr);

二、忽略大小写比较

if(str1.equals("Hello World")){
            System.out.println("相等");
        }else {
            System.out.println("不相等");
        }

boolean isEqualIgnoreCase = str.equalsIgnoreCase(anotherStr);

三、比较返回一个数 

int compareResult = str.compareTo(anotherStr);

如果两个字符串相等,则返回值为0。 

如果调用compareTo()方法的字符串比传入的字符串小,则返回一个负整数。

如果调用compareTo()方法的字符串比传入的字符串大,则返回一个正整数。

具体返回值的计算规则如下:

  1. 如果两个字符串相等,则返回值为0。

  2. 如果调用compareTo()方法的字符串在按字典顺序排列时排在被比较的字符串之前,则返回一个负整数。这个负整数实际上是两个字符串在第一个不同字符上的 Unicode 编码点的差值。

  3. 如果调用compareTo()方法的字符串在按字典顺序排列时排在被比较的字符串之后,则返回一个正整数。这个正整数实际上也是两个字符串在第一个不同字符上的 Unicode 编码点的差值。

以下是ASCII与Unicode的介绍博客 

Unicode与ASCII-CSDN博客

在Java中,字符串是以Unicode编码的方式存储的。因此,比较字符串时通常会涉及到比较其中包含的字符的Unicode编码点。

compareTo()方法在比较字符串时也是根据两个字符串中的对应字符的Unicode编码点来确定字符串的大小关系的。

了解Unicode编码点的概念对理解字符串比较以及其他涉及Unicode字符集的操作非常重要。Unicode编码点的唯一性可以帮助确保不同的字符在计算机中得到正确的表示和处理。 

查找字符或子串

使用indexOf与lastIndexOf 

indexOf

如果找到相关的字符就返回该字符第一次出现的位置(从0开始数)

lastIndexOf

如果找到相关的字符就返回该字符最后一次出现的位置(从0开始数)

 

替换字符串

有以下四种替换字符串的方法

前三种的替换都是全局调用

replaceAll的使用需要用正则表达式

replaceFirst则就是只替换第一次遇到的

replace与replaceAll的区别:

由于replaceAll使用正则表达式解析,处理速度通常比直接的replace慢,尤其是在处理大量数据时。因此,在不需要正则表达式功能时,优先考虑使用replace。

去除空白

一、trim()

去除字符串首尾的空格 

String str13 = " Hello World ";
String str14 = str13.trim();
System.out.println(str14);//Hello World

使用这个方法会返回一个新的字符串 

二、strip()

 

Java 11起,功能与trim相同,但更高效

 strip()                   删去头尾的空格

stripLeading()       删去头部的空格

stripTrailing()        删去尾部的空格

转换大小写

toUpperCase();  转化为大写

toLowerCase();  转化为小写

String str1 = "Hello World";
String str19 = str1.toLowerCase();
System.out.println(str19);   //hello world
String str20 = str1.toUpperCase();
System.out.println(str20);   //HELLO WORLD

分割字符串

String[] parts = str.split(","); // 根据指定分隔符拆分字符串为数组

String sentence = "Hello World this is Java";
String[] words = sentence.split(" ");
// words 现在是 ["Hello", "World", "this", "is", "Java"]

判断字符串特性

boolean str2 = str.isEmpty();

判断字符串是否为空

boolean str2 = str.isBlank();

Java 11起,判断字符串是否为空白(空格、制表符、换行符或空字符串)

连接字符串

一、concat()

String str1 = "Hello World";
String str2 = new String(str1);
String str21 =str1.concat(str2);
System.out.println(str21);

//Hello WorldHello World

二、join()

使用分隔符连接字符串数组

String str =String.join("_","str1","str2");
System.out.println(str);

//str1_str2

其他操作

转换为字节数组

byte[] bytes = str.getBytes();

格式化字符串

String str23 = String.format("hello|%20s|",str1);
System.out.println(str23);

//输出的结果是:hello|         Hello World|

反转字符串(非String类直接方法,但常用)

String reversed = new StringBuilder(str).reverse().toString(); 


StringBuilder


构造方法                

StringBuilder():创建一个空的StringBuilder实例。

StringBuilder(String str):创建一个StringBuilder实例,并将其初始化为指定的字符串内容。

StringBuilder(int a): 创建一个StringBuilder实例,指定空间

public class Main {
    public static void main(String[] args) {
       StringBuilder a = new StringBuilder();
       StringBuilder aa= new StringBuilder(4);
       StringBuilder aaa= new StringBuilder("abd");

       System.out.println(aaa);//abd
    }
}

添加元素        

 append(char[] str,int a,int len)

复制包含a到len-1索引的元素 

StringBuilder a = new StringBuilder();
char[] b={'a','b','c'};
a.append(b,0,2);
System.out.println(a);//ab

 append(CharSequence s,int start,int end)与以上功能一致

appendCodePoint(int codePoint) 

StringBuilder sb = new StringBuilder("Hello");
sb.appendCodePoint(128516); // 将笑脸 😊 的Unicode代码点添加到StringBuilder末尾
System.out.println(sb); // 输出:Hello😊

用于向StringBuilder对象中追加指定的Unicode代码点。 

插入

insert(int offset, CharSequence s):将指定的字符序列插入此序列中指定的位置。

insert(int offset, char[] str)、insert(int offset, char c)、insert(int offset, boolean b)等:在指定位置插入字符、字符数组或基本类型的值

替换

replace(int start, int end, String str):用指定字符串替换此序列中指定位置的子字符串。

删除

delete(int start, int end):删除此序列中指定位置之间的字符。

查找与索引

indexOf(String str)、lastIndexOf(String str):查找指定字符串第一次或最后一次出现的索引位置

子串

substring(int start)、substring(int start, int end):返回此序列中一个子序列的字符串。

转换

toString():将当前StringBuilder对象转换为字符串。

长度与容量管理

length():返回此序列中的字符数量。

capacity():返回当前容量。

ensureCapacity(int minimumCapacity):确保容量至少为指定的最小值。

其他

reverse():将此序列中的字符逆序。

setCharAt(int index, char ch):将给定索引处的字符设置为指定字符。

charAt(int index):返回此序列中指定索引处的字符。

setLength(int newLength):设置字符序列的长度,如果新长度小于原长度,则截断;如果大于原长度,则填充空字符。


Stringjoiner


 使用需要加入

import  java.util.StringJoiner

构造方法:

StringJoiner(CharSequence delimiter)

创建一个 StringJoiner 实例,使用指定的分隔符,前缀和后缀默认为空字符串。

StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

创建一个 StringJoiner 实例,可以指定分隔符、前缀和后缀。

添加元素:

StringJoiner add(CharSequence newElement)

将指定的元素追加到此 StringJoiner 的内部缓冲区,之间插入分隔符。如果这是第一次调用 add,则在添加元素之前会先添加前缀。

合并 :

StringJoiner merge(StringJoiner other)

将另一个 StringJoiner 的元素合并到此 StringJoiner,不会添加其他 StringJoiner 的前缀,但会正确应用分隔符和后缀。

设置空值:

StringJoiner setEmptyValue(CharSequence emptyValue)

设置当没有添加任何元素时返回的字符串。默认情况下,如果没有添加元素,toString 方法将返回由前缀和后缀组成的字符串。

获取结果字符串:

String toString()

返回由已添加的元素构成的字符串,元素之间以分隔符隔开,并且在开始处有前缀,在结束处有后缀。如果没有添加任何元素,则返回通过 setEmptyValue 设置的值或默认构造的前缀+后缀。


String/StringBuilder/Stringjoiner不同点

1. String

不可变性:String类代表的是不可变的字符序列。一旦创建了一个String对象,它的内容就不能改变。任何对String的操作,比如连接、替换等,都会返回一个新的String对象,而不是修改原有的对象。

性能:由于其不可变性,在进行大量的字符串拼接操作时,会产生大量的临时字符串对象,可能导致性能下降和内存消耗增加。

适用场景:适用于字符串内容不经常改变,或不需要频繁进行修改操作的情况,比如常量定义、比较字符串等。

2. StringBuilder

可变性:StringBuilder是String的一个可变版本,专为字符串的修改设计。它允许我们在原来的字符序列基础上进行添加、删除和替换操作,而不需要创建新的对象。

性能:相较于使用+操作符或String的拼接,StringBuilder在进行大量字符串操作时性能更好,因为它减少了内存中对象的创建。

适用场景:适用于需要频繁修改字符串内容的情况,如构建SQL语句、拼接HTML代码等。

3. StringJoiner

StringJoiner是Java 8引入的一个工具类,专门用于以某种分隔符连接多个字符串,形成一个新的字符串。它比直接使用StringBuilder或String的拼接更加方便和直观。

特点:StringJoiner允许你指定前缀、后缀以及分隔符,非常适合于生成CSV样式的数据、日志记录等。


字符串底层相关原理

1、字符串存储的内存原理

String s = “abc”

特点:

此时字符串abc是存在字符串常量池中的。

先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。

所以,直接赋值的方式,代码简单,而且节约内存。

2、new关键字,一定是在堆里面开辟了一个小空间。

String s1 = new String(“abc”);

String s2 = “abc”;

s1记录的是new出来的,在堆里面的地址值。

s2是直接赋值的,所以记录的是字符串常量池中的地址值。

3、如果比较的是基本数据类型:比的是具体的数值是否相等。

如果比较的是引用数据类型:比的是地址值是否相等。

==只能用于比较基本数据类型。不能比较引用数据类型。

4、字符串拼接的底层原理

如果拼接字符串的没有变量,那再编译时会触发字符拼接优化机制,编译时拼接的多个字符或者字符串就已经是最终结果。

JDK8字符串拼接的底层原理

StringBuilder的扩容原理如下:

原始容量:当创建一个新的StringBuilder对象时,会初始化一个默认容量的字符数组,通常为16个字符长度。

扩容策略:当需要追加的字符个数超出了当前字符数组的容量时,StringBuilder会通过如下公式计算新的容量:
newCapacity = (oldCapacity + 1) * 2

        StringBuilder he = new StringBuilder();
        he.append("aaa,0,2");
        System.out.println(he.capacity());//16
        System.out.println(he.length());//7

        he.append("sjfdklsflslfjalsflaajslf");
        System.out.println(he.capacity());//34
        System.out.println(he.length());//31

        he.append("sj]]f");
        System.out.println(he.capacity());//70
        System.out.println(he.length());//36

复制元素:在扩容之前,会先检查当前容量是否能够容纳新的字符,如果不行则会创建一个新的字符数组,长度为新的容量。接着会将原来数组中的元素复制到新的数组中。

扩容操作:最后,StringBuilder会将新的字符数组设置为内部的字符数组,从而完成扩容操作。

需要注意的是,每次扩容都会导致字符数组的拷贝,这样会增加一定的开销。

为了减少扩容的次数,可以在创建StringBuilder对象时指定一个较大的初始容量,以避免多次扩容操作,提高性能。

;