Java
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();