跳至主要內容

Java

LincZero大约 6 分钟

Java

目录

字符类型

String类(字符串)

API: java.lang.String 1.0(包含了50多个方法)

原理类

简概

从概念上讲,Java字符串就是Unicode字符序列

Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,很自然地叫做String

(Python有但用起来有点奇怪(存储字符串的变量可变,字符串元素不可变,为区别于常量其更贴切的说法是元素不可变性),这有点不像数组)

String e = "";				// an empty string
String greeting = "Hello";

不可变字符串

和Python字符串一样,Java的String类字符串也是不可修改的。String类没有提供用于修改字符串的方法。 如果希望将greeting(“Hello”)的内容修改为“Help!”,不能直接地将greeting的最后两个位置的字符修改为‘p’和‘!’。 这对于C程序员来说,将会感到无从下手。

技巧(拼接)

在Java中实现这项操作非常容易。首先提取需要的字符,然后再拼接上替换的字符串:

greeting = greeting.substring(0,3) + "p!";	// Help!
底层原理
  • 原理:可以修改字符串变量greeting,让它引用另外一个字符串,这就如同可以将存放3的数值变量改成存放4一样。

  • 效率:这样做是否会降低运行效率呢?看起来好像修改一个代码单元要比创建一个新字符串更加简洁。

    答案是:也对,也不对。的确,通过拼接“Hel”和“p!”来创建一个新字符串的效率确实不高。

    但是,不可变字符串却有一个优点:编译器可以让字符串共享

    总而言之,Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。查看一下程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较

长度 length和codePointCount

长度,length 和 codePointCount

String s = "\uD835\uDD46 is the set of octonions";
// 其中\uD835\uDD46也可写作U+1D546或𝕆,是一个八元数的数学符号,需要两个代码单元
int n = s.length();								// 返回`代码单元的数量`(采用UTF-16编码表示的给定字符串)
// is 26,  \uD835\uDD46为2
int n = s.codePointCount(0, s.length());		// 返回`码点的数量`(实际长度)
// is 25,  \uD835\uDD46为1

码点和代码单元(除非对底层的代码单元感兴趣,否则不要使用)

char first = s.charAt(1);				// 将返回位置n的代码单元(相当于取数组)
//  调用s.charAt(1);返回的不是该字符的后一个字符,而是第二个代码单元。为了避免这个问题,不要使用char类型。

码点遍历

// 顺序遍历
int cp = sentence.codePointAt(i);
if(Character.isSupplementaryCodePoint(cp)) i+=2;
else i++;

// 或者回退
i--;
if(Character.isSurrogate(sentence.charAt(i))) i--;
int cp = sentence.codePointAt(i);

// 更容易的办法是使用codePoints方法,它会生成一个int值的“流”,每个int值对应一个码点。
int[] codePoints = str.codePoints().toArray();
// 反之,要把一个码点数组转换为一个字符串,可以使用构造函数
String str = new String(codePoint, 0, codePoints.length);

String 常用 API

拼接 +

String expletive = "Expletive";
String PG13 = "deleted";
String message = expletive + PG13;

// 还可以拼接数值类型
String message = "age:" + 13;

子串 substring

有点类似于Python中的切片操作,不过Python的操作更字面量些

String greeting = "Hello";
String s = greeting.substring(0,3);	// “Hel"

join

多个字符串放在一起,用一个定界符分隔

String s_all = String.join(" / ", "S", "M", "L", "XL");
// s_all is "S / M / L / XL"

检测字符串是否相等 equals

s.equals(t);						// 返回布尔,区分大小写
"Hello".equal(greeting);			// 可以使用字面量
"Hello".equalsIgnoreCase("hello");	// 不区分大小写
// 一定不要使用==运算符检测两个字符串是否相等!这个运算符只能够确定两个字符串是否放置在同一个位置上
// 这点和C/C++一样,因为JavaString本质上是指针
greeting.compareTo("Hello")==0;		// 更类似于C strcmp的函数

空串与Null串

检查方法

// 空串
if(str.length()==0);
if(str.equals(""));

// Null串
// String变量还可以存放一个特殊的值,名为null,这表示目前没有任何对象与该变量关联
if(str==null);
if(str!=null && str.length()!=0);

// 即不是空串又不是null,则用&&来检测

String API

// 其他
char charAt(int index);											// 返回给定位置的代码单元(除非对底层的代码单元感兴趣,否则不要使用)
int codePointAt(int index);										// 返回从给定位置开始的码点
int offsetByCodePoints(int startIndex, int cpCount);			// 返回从startIndex开始,cpCount个码数
int compareTo(String other);									// 按字典顺序,看字符串若位于other前则负数,之后正数,相等为0
IntStream codePoints();											// 将字符串码点作为一个流返回,调用toArray将它们放在一个数组中
new String(int[] codePoints, int offset, int count);			// offset开始的count个码点构造一个新字符串

// 布尔类
boolean empty();												// 是否为空
boolean blank();												// 是否为空或由空格组成
boolean equals(Object other);									// 两字符是否相等,不忽略/忽略大小写
boolean equalsIgnoreCase(String other);							//
boolean startsWith(String prefix);								// 前缀/后缀
boolean endWith(String suffix);									//

// 序列/个数类
int indexOf(String str);										// 从cp开始,返回匹配到的序列,不存在则返回-1
int indexOf(int cp);											//
int indexOf(int cp, int fromIndex);								//
int lastIndexOf(String str);									// 从最后开始匹配
int lastIndexOf(String str, int fromIndex);						//
int lastindexOf(int cp);										//
int lastindexOf(int cp, int fromIndex);							//
int length();													// 返回字符串代码单元的个数
int codePointCount(int startIndex, int endIndex);				// 返回字符串片段中码点的个数

// 返回新字符串系列
String replace(CharSequence oldString, CharSequence newString);	// 返回新字符串,用newString替换oldString
String substring(int beginIndex);								// 返回新字符串,子串
String substring(int beginIndex, int endIndex);					//
String toLowerCase();											// 返回新字符串,全小写/全小写
String toUpperCase();											//
String trim();
String strip();													// 返回新字符串,删除头尾空格或空白
String join(CHarSequence delimiter, CharSequence... elements);	// 返回新字符串,用给定的定界符连接所有元素
String repeat(int count);										// 返回新字符串,将当前字符串重复count次

StringBuilder类(构建字符串类)

API: java.lang.StringBuilder 5.0

构造

有些时候,需要由较短的字符串构建字符串,例如,按键或来自文件中的单词。采用字符串连接的方式达到此目的效率比较低。

每次连接字符串,都会构建一个新的String对象,既耗时,又浪费空间。使用StringBuilder类就可以避免这个问题的发生。

StringBuilder builder = new StringBuilder();

当每次需要添加一部分内容时,就调用append方法

builder.append(ch);		// 添加单个字符
builder.append(str);	// 追加字符串

类型转换

在需要构建字符串时就调用toString方法,将可以得到一个String对象

String completedString = builder.toString();