> 文章列表 > Java字符串对象(String|StringBuffer|StringBuilder|StringJoiner)

Java字符串对象(String|StringBuffer|StringBuilder|StringJoiner)

Java字符串对象(String|StringBuffer|StringBuilder|StringJoiner)

String(引用类型)

(1)String是一个引用类型,它本身也是一个class。但是,Java编译器对String有特殊处理,即可以直接用“…”来表示一个字符串
(2)实际上字符串在String内部是通过一个char[]数组表示的;所以可以使用new String(new char[])来创建字符串
(3)Java字符串的一个重要特点就是字符串对象不可变,引用可变。这种不可变性是通过内部的private final char[]字段,以及没有任何修改char[]的方法实现的

两个字符串比较,必须总是使用equals()方法,要忽略大小写比较,使用equalsIgnoreCase()方法

创建字符串(4种)

1.引用字符串常量

直接将字符串常量赋值给String类型变量

String a = "123456";

2.利用构造方法实例化

使用new关键字创建String对象

String a = new String("It’s a dream");

3.利用字符数组实例化

定义一个字符数组charArrays,使用该字符数组创建一个字符串

char[] charArrays = {'t','i','m','e'};
String a = new String(charArrays);		
// 输出:time

4.提取字符数组中的一部分创建字符串对象

定义一个数组,从该字符数组索引3的位置开始,提取2个元素,组成一个新的字符串

char[] charArrays = {'时','间','就','是','金','钱'};
String a = new String(charArrays, 3, 2);	
// 输出:金钱

String实例方法

1.连接字符串(+、+=)

使用+、+=拼接字符串

String a = "abc";
String b = "123";
String c = a + b + "!"; // 使用+拼接字符串。c=abc123!String d = "拼接字符串";
d += c; // d = 拼接字符串abc123!

2.将指定的字符串连接到此字符串结尾:concat()

wantOnly.concat(str);

wantOnly:原字符串
str:原字符末尾拼接的字符串

3.判断子字符串是否存在:contains()

判断字符串中是否包含指定内容(boolean)

wantOnly.contains(str);

wantOnly:任意字符串
str:查询的子字符串

String str = "肉";
boolean contains1 = str.contains("肉");  //true
boolean contains2 = str.contains("内");  //false

4.获取字符串长度:length()

String num = "123456789";
int size = num.length();

5.获取指定字符:charAt()

wantOnly.charAt(index);

wantOnly:任意字符串对象
index:char值的索引

String str = "床前明月光";
char chr = str.charAt(3); // 月

6.获取子字符串索引位置:indexOf()

用于查找当前字符串中字符或子串,返回字符或子串在当前字符串中从左边起首次出现的位置,若没有出现则返回-1
indexOf(searchStr)


wantOnly.indexOf(searchStr);

wantOnly:任意字符串对象
searchStr:要搜索的字符串

String str = "where are you going";
int size = str.indexOf("e");  // 2

如果是字符串返回第一个字符位置

indexOf(searchStr, formIndex):获取子字符串索引位置,指定开始位置

wantOnly.indexOf(searchStr, fromIndex);

wantOnly:任意字符串对象
searchStr:要搜索的子字符串
fromIndex:开始搜索的索引位置(int)

String str = "It’s a dream";
int size = str.indexOf("s",1);  // 3

lastIndexOf(searchStr):返回指定子字符串最后出现的索引

wantOnly.lastIndexOf(searchStr);

wantOnly:任意字符串对象
searchStr:要搜索的字符串

lastIndexOf(searchStr, formIndex):指定位置搜索最后出现的索引

wantOnly.lastIndexOf(searchStr, fromIndex);

wantOnly:任意字符串对象
searchStr:要搜索的子字符串
fromIndex:开始搜索的索引位置

7.判断是否以指定字符串开始或结尾(都是boolean类型)

(1)startsWith(开始)

wantOnly.startsWith(prefix);

wantOnly:任意字符串
prefix:作为前缀的字符串

String wantOnly = "这是好东西";
boolean size = wantOnly.startsWith("这");

指定开始位置

wantOnly.startsWith(prefix, index);

wantOnly:任意字符串对象
index:开始查找的位置

(2)endsWith(结尾)

wantOnly.endsWith(suffix);

wantOnly:任意字符串
suffix:指定的后缀字符串

8.获取字符数组:toCharArray()

将字符串转换成一个字符数组

wantOnly.toCharArray();String str = "这是一个字符串";
char[] ch = str.toCharArray();

9.截取字符串:substring()

wantOnly.substring(int beginIndex);

wantOnly:任意字符串
beginIndex:起始索引(int,包括)

String wantOnly = "这是一颗心";
String subStr = wantOnly.substring(2);  // 一颗心

指定开始位置

wantOnly.substring(int beginIndex, int endIndex);

wantOnly:任意字符串
beginIndex:起始索引(包括)
endIndex:结束索引(不包括)

String wantOnly = "优秀的人还是优秀";
String subStr = wantOnly.substring(0, 4); // 优秀的人

10.字符串替换:replace()

replace()

wantOnly.replace(oldstr, newstr);

wantOnly:任意字符串
oldstr:要被替换的字符串序列
newstr:替换后的字符串序列

String wantOnly = "明月几时有,把酒问青天";
String reStr = wantOnly.replace("月", "日"); // 明日几时有,把酒问青天

replaceAll()
将指定字符串替换成新的字符串

wantOnly.replaceAll(regex,replacement);

wantOnly:任意字符串
regex:被替换的字符串或正则表达式
replacement:替换后的字符串

replaceFirst()
将第一个指定的字符串替换成新的字符串。支持正则表达式

wantOnly.replaceAllFirst(regex,replacement);

wantOnly:任意字符串
regex:第一个被替换的字符串或正则表达式
replacement:替换后的字符串

String wantOnly = "8I want to marry you.";
String replaceFirst = wantOnly.replaceFirst("\\\\d",":");
System.out.println(replaceFirst);//:I want to marry you.

11.字符串分割:split()

split(regex)
根据给定的分隔符对字符串进行拆分,支持正则表达式,最后返回一个字符串数组

wantOnly.split(regex);

wantOnly:任意字符串
regex:分隔符表达式

String wantOnly = "我,想,打,你";
String[] strArray = wantOnly.split(","); // 让字符串按照“,”分割
String string = Arrays.toString(strArray);
System.out.println(string); //[我, 想, 打, 你]

split(regex,limit)
根据分隔符对字符进行拆分,并限定拆分次数。支持正则表达式

wantOnly.split(regex, limit);

wantOnly:任意字符串
regex:分隔符表达式
limit:限制的分割次数(int)

String wantOnly = "a,b,c";
String[] arrStr = wantOnly.split(",", 2); // [a] [b,c]
for(String arr : arrStr) {System.out.println(arr);
}

12.大小写转换:toLowerCase()、toUpperCase()

wantOnly.toLowerCase();  // 转换为小写
wantOnly.toUpperCase();  // 转换为大写
wantOnly.toLowerCase(Locale);
wantOnly.toUpperCase(Locale);

Locale
java.util.Locale主要在软件的本地化时使用。它本身没有什么功能,更多的是作为一个参数辅助其他方法完成输出的本地化

Locale myLocale = Locale.getDefault();
System.out.println(myLocale.getCountry());   // CN
System.out.println(myLocale.getLanguage());  // zh
System.out.println(myLocale.getDisplayCountry());  // 中国
System.out.println(myLocale.getDisplayLanguage()); // 中文

13.去除空白内容:trim()、replaceAll()

trim():去除首尾空白内容

wantOnly.trim();

replaceAll():去除所有空白内容
利用正则表达式\\s,将所有空白内容换成空字符

String str = "  1       2     3";
String newstr = str.replaceAll("\\\\s", "");  // 123

14.比较字符串是否相等:equals()、equalslgnoreCase()

boolean equals(Object anotherObject)
比较当前字符串和参数字符串,在两个字符串相等的时候返回true,否则返回false

wantOnly.equals(str);

wantOnly:任意字符串
str:进行比较的字符串

str1.equals(str2);

注意
(1)若两边的变量是基本类型,则只要它们数值相等,就判断这两个变量相等,返回true。
(2)若
两边的变量是引用变量,则 ==比较的是这两个变量的内存地址,只有它们指向同一个对象时,才会返回true

equals比较的是两个对象的内容,如果不重写equals方法,自动调用Object的equals方法(重写后比较的是内存地址),则和“==”一样。但String和Integer,默认重载了Object类的equals方法(重载后比较的是对象的内容)

boolean equalslgnoreCase(anotherString)
字符串对象比较,忽略大小写(长度相等,并且字符相等(忽略大小写),则认为相等)

wantOnly.equalslgnoreCase(anotherString);

wantOnly:任意字符串
anotherString:进行比较字符串

15.判断字符串是否为空:==、equals()

需要判断str是否等于null和””

wantOnly == null
wantOnly.equals("");

16.格式化字符串:format()

使用指定格式字符串和参数返回一个格式化字符串,格式化后的新字符串使用本地默认的语言方法

wantOnly.format("", 0);

format:任意字符串
args:格式字符串中由格式说明引用的参数,如果还有格式说明符以外的参数,则忽略这些额外的参数。此参数是可变的,可以为0

format(Locale locale, String format, Object… args);

参数 描述
locale 格式化过程中要应用的语言环境
format 格式字符串
args 格式字符串中由格式说明符引用的参数,如果还有格式说明符以外的参数,则忽略这些额外的数目是可变的,可以为0

17.字符串比较:compareTo()

int compareTo(String anotherString)
对字符串内容按字典顺序进行大小比较,通过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0
比较规则:拿出字符串的第一个字符与参数的第一个字符进行比较,如果两者不等,比较结束,返回两者的ascii差。这里有一点需要注意:如果两个字符串的长度不同,并且一个字符串与另一个字符串的前面N个字符相等,那么这个方法返回返回两个字符串长度之差

int compareToIgnore(String anotherString)
与compareTo方法相似,但忽略大小写

String类方法

返回值都是static String

方法 描述
valueOf(int i) 返回int参数的字符串int形式
valueOf(long l) 返回long参数的字符串long形式
valueOf(char c) 返回char参数的字符串char形式
valueOf(char[] data) 返回char数组参数的字符串char形式
valueOf(char[] data, int offset, int count) 返回char数组参数的特定子阵列的字符串char形式
valueOf(float f) 返回float参数的字符串float形式
valueOf(double d) 返回double参数的字符串double形式
valueOf(boolean b) 返回boolean参数的字符串boolean形式
valueOf(Object obj) 返回Object参数的字符串Object形式

StringBuilder(JDK 1.5)

(1)StringBuilder是可变对象,用来高效拼接字符串
(2)StringBuilder支持链式操作,实现链式操作的关键是返回实例本身
(3)StringBuffer是StringBuilder的线程安全版本,现在不需要使用

Java编译器对String做了特殊处理,可以直接用“+”拼接字符串。String虽然可以直接拼接字符串。但是,在循环中,每次循环都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率

注意:对于普通的字符串“+”操作,并不需要将其改写为StringBuilder,因为Java编译器在编译时就自动把多个连续的“+”操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连接操作优化为数组复制或者StringBuilder操作

为了能高效拼接字符串,Java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区。这样,往StringBuilder中新增字符时,不会创建新的临时对象。查看StringBuilder的源码,可以发现,进行链式操作的关键:定义的append()会返回this,这样,就可以不断调用自身的其他方法

注意:对于普通的字符串“+”操作,并不需要将其改写为StringBuilder,因为Java编译器在编译时就自动把多个连续的 + 操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连接操作优化为数组复制或者StringBuilder操作

StringBuffer是Java早期的一个StringBuilder的线程安全版本,它通过同步来保证多个线程操作StringBuffer也是安全的,但是同步会带来执行速度的下降。StringBuilder和StringBuffer接口完全相同

进行链式操作

public class Main {public static void main(String[] args) {StringBuilder sb = new StringBuilder(1024);sb.append("Mr ").append("Bob").append("!").insert(0, "Hello, ");System.out.println(sb.toString());}
}

查看StringBuilder的源码,可以发现,进行链式操作的关键是,定义的append()方法会返回this,这样,就可以不断调用自身的其他方法

不断增加的计数器

仿照StringBuilder,也可以设计支持链式操作的类

1.Adder.java

class Adder {private int sum = 0;public Adder add(int n) { // 求和sum += n;return this;}public Adder inc() { // 加1sum++;return this;}public int value() { // 值return sum;}
}

2.Test.java

public class Test {// 链式操作public static void main(String[] args) {Adder adder = new Adder();adder.add(3).add(5).inc().add(10);System.out.println(adder.value());}
}	

StringBuffer(JDK 1.0)

StringBuffer是线程安全的可变符序列,一个类似于String的字符串缓冲区String创建的字符串对象是不可修改的,StringBuffer类创造的字符串序列是可修改的,且实体容量会随着存放的字符串增加而自动增加

StringBuffer,这是Java早期的一个StringBuilder的线程安全版本,它通过同步来保证多个线程操作StringBuffer也是安全的,但是同步会带来执行速度的下降
StringBuilder、StringBuffer接口完全相同

创建StringBuffer类

创建一个StringBuffer对象必须用new方法

StringBuffer ss = new StringBuffer();       // 无初始值
StringBuffer ss = new StringBuffer("asd"); // 初始值为asd
StringBuffer ss = new StringBuffer(16);    // 初始容量为32个字符

方法

1.添加字符append()

将参数换成字符串,将所有所得字符串中的字符追加到此序列中(跟String类型的concat类似)

sbf.append(obj)

sbf:任意StringBuffer对象
obj:任意数据类型的对象,例如Sting、double、int、Boolean等,都转变此成字符串的表示形式

2.将给定索引处的字符修改为setCharAt()

sbf.chsetCharAt(int index,char ch);

sbf:任意StringBuffer对象
index:被替换的字符
ch:替换字符

3.将一个字符串插入此字符串序列中insert()

sbf.insert(int offset,String str)

sbf:任意StringBuffer对象
offset:插入的索引
str:插入的字符串

4.将字符串反序输出(也就是索引反序)reverse()

sbf.reverse();

5.移除序列子字符串中的字符delete()

移除该序列的子字符串中的字符,该子字符串是从指定的索引start处开始,一直到索引end处结束

sbf.delete(int start,int end);

sbf:任意StringBuffer对象
start:起始索引(包含)
end:结束索引(不包含)

其他方法

方法 描述
sbf.length() 获取字符串长度
sbf.charAt(5) 获取索引为5的字符
sbf.indexOf(str) 获取str所在字符索引位置
sbf.substring(0,2) 截取索引0-2之间的字符串
sbf.replace(2,5,”123”) 将索引2-5之间替换成123

三者相互转换

// String转换为StringBuffer、StringBuilder
String str = "str123";
// String-->StringBuffer
StringBuffer sb = new StringBuffer(str); 
// String-->StringBuilder
StringBuilder sd = new StringBuilder(str);// StringBuffer、StringBuilder转换为String
// StringBuffer-->String
String a = sb.toString(); 
// StringBuilder-->String
String b = sd.toString();// StringBuffer相互转换StringBuilder
// StringBuilder-->StringBuilder
StringBuffer sb1 = new StringBuffer(sd.toString());   
// StringBuffer-->StringBuilder
StringBuilder sd1 = new StringBuilder(sb.toString()); 

三者比较

类名 String StringBuilder StringBuffer
对象类型 字符串常量 字符串常量 字符串常量
线程安全性 不安全 不安全 安全
执行效率

String只能赋值一次,每一次内容发生改变都生成了一个新的对象,如何原有的对象引用新的对象
StringBuffer、StringBuilder则不同,每次操作都是对自身对象做操作,而不是生成新的对象

StringBuffer和StringBuilder
StringBuffer和StringBuilder也存在不同之处,StringBuffer的方法使用了“synchronized”关键字进行修饰,这样保证了同时最多只有一个线程可以运行这些方法,保证了线程的安全

StingBuilder则不具备这样的特点。反过来说,正因为StringBuilder没有线程安全机制,运行起来就不用考虑线程加锁,所以运行效率会比StringBuffer要高

适用场合

(1)操作少、数据少、用String
(2)单线程、操作多、数据多、用StringBuilder
(3)多线程、操作多、数据多、用StringBuffer
要高效拼接字符串,应该使用StringBuilder

StringJoiner

原有的StringBuilder太死板,不支持分割;类似分隔符拼接数组的需求很常见,所以Java标准库还提供了一个StringJoiner

StringJoiner是java.util包中的一个类,用于构造由定界符分隔的字符序列(可选),并提供的前缀开始、后缀结尾。虽然这也可以在StringBuilder类的帮助下在每个字符串之后附加分隔符,但StringJoiner提供了简单的方法来实现,而无需编写大量代码

StringJoiner类共有2个构造函数,5个公有方法。其中最常用的方法就是add()和toString(),类似于StringBuilder中的append方法和toString方法

实现原理:依赖StringBuilder实现,性能和StringBuilder差不多,同样也是非线程安全的

在向StringJoiner添加内容之前,有时情况下,其sj.toString()将返回prefix + suffix。但是,如果调用setEmptyValue()方法,则将返回提供的emptyValue。这可以使用,例如,创建使用组表示法来表示空集,即一个字符串时“{}”,其中prefix是“{”,所述suffix是“}”,没有什么已被添加到StringJoiner

查看源码,可以发现,StringJoiner内部实际上就是使用了StringBuilder,所以拼接效率和StringBuilder几乎是一模一样的

StringJoiner指定“开头”和“结尾”

String[] names = {"Bob", "Alice", "Grace"};
var sj = new StringJoiner(", ", "Hello ", "!"); // var是JDK 10新特性
for (String name : names) {
sj.add(name);
}
System.out.println(sj.toString());

输出:Hello Bob, Alice, Grace!

拼接List

List<String> list = new ArrayList<String>();
list.add("Red");
list.add("Green");
list.add("Blue");
StringJoiner stringJoin = new StringJoiner(",", "PREFIX-", "-SUFFIX");
for (String str : list) {stringJoin.add(str);
}
System.out.println(stringJoin.toString());

输出:PREFIX-Red,Green,Blue-SUFFIX

构造方法

(1)StringJoiner(CharSequence delimiter)
(2)StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
构造一个StringJoiner,使用分隔符、拼接前缀、拼接后缀

参数 描述
delimiter 分隔符。并不是可变字符串的初始值
prefix 拼接后的字符串的前缀
suffix 拼接后的字符串的后缀

常用方法

(1)StringJoiner add(CharSequence newElement):增加需要分割拼接的字符串

将给定的副本CharSequence值作为下一个元素StringJoiner值

(2)int length():获取分割拼接后长度

返回此StringJoiner的String表示形式的StringJoiner

(3)StringJoiner merge(StringJoiner other):增加需要分割拼接的StringJoiner

添加给定StringJoiner的内容,不带前缀和后缀作为下一个元素(合并另外一个StringJoiner内容,不带前后缀。跟add()效果一个,不过是一个拼接完成的StringJoiner在进行拼接)

(4)StringJoiner setEmptyValue(CharSequence emptyValue):空时输出

设置在确定此StringJoiner的字符串表示形式时要使用的字符序列,并且尚未添加任何元素,即它为空时
CharSequence是一个接口,提供参数必须实现此接口(String、StringBuilder、StringBuffer)

(5)String toString():转为字符串

返回当前值,包括prefix前缀、最终由delimiter分隔的值、suffix后缀
如果在这种情况下未使用add()添加任何元素,否则返回prefix + suffix或字符emptyValue

String.join()

String还提供了一个静态方法join(),这个方法在内部使用了StringJoiner来拼接字符串,在不需要指定“开头”和“结尾”的时候,用String.join()更方便
static String join(CharSequence delimiter, CharSequence… elements)

String[] names = {"Bob", "Alice", "Grace"};
var sj = String.join(", ", names);
// 输出sj值:Bob, Alice, Grace

如果日常开发中,需要进行字符串拼接,如何选择?
(1)如果只是简单的字符串拼接,考虑直接使用"+"即可
(2)如果是在for循环中进行字符串拼接,考虑使用StringBuilder和StringBuffer
(3)如果是通过一个集合(如List)进行字符串拼接,则考虑使用StringJoiner
(4)如果是对一组数据进行拼接,则可以考虑将其转换成Stream,并使用StringJoiner处理


上一篇:Java数组                        下一篇:Java面向对象