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面向对象