Fork me on GitHub

Java编程思想———字符串

不可变String

String对象是不可变的,String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容,而最初的String对象则丝毫未动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Immutable {
public static String upcase(String s) {
return s.toUpperCase();
}
public static void main(String[] args) {
String q = "howdy";
System.out.println(q);
String qq = upcase(q);
System.out.println(qq);
System.out.println(q);
}
}

//output
howdy
HOWDY
howdy

重载 “+” 与StringBuilder

String对象是不可变的,不可变性会带来一定的效率问题。为String对象重载的“+”操作符就是一个例子。(用于 “+” 与 “+=” 是Java中仅有的两个重载过的操作符,而Java并不允许程序员重载任何操作符)。

虽然编译器已经自动优化,用StringBuilder实现字符串拼接操作来避免生成多余对象,但是还是建议对于复杂的字符串拼接,在代码中主动使用StringBuilder,因为这样效率最高。

无意识的递归

Java中的每个类从根本上都是继承自Object,标准容器类自然也不例外。因此容器类都有toString()方法,并且覆写了该方法,使得它生成的String结果能够表达容器自身,以及容器所包含的对象。例如ArrayList.toString(),它会遍历ArrayList中包含的的所有对象,调用每个元素上的toString()方法。

如果你希望toString()方法打印出对象的内存地址,也许你会考虑使用this关键词:

1
2
3
4
5
6
7
8
9
10
11
12
public class InfiniteRecursion {
public String toString() {
return "InfiniteRecursion address: " + this + "\n"; //this导致递归调用
}
public static void main(String[] args) {
List<InfiniteRecursion> v = new ArrayList<InfiniteRecursion>();
for(int i = 0; i < 10; i++) {
v.add(new InfiniteRecursion());
}
System.out.println(v);
}
}

当你创建了InfiniteRecursion对象,并将其打印的时候,你会得到一串非常长的异常。如果你将该InfiniteRecursion对象存入一个ArrayList中,然后打印该ArrayList,你也会得到同样的异常。编译器尝试将this转换成一个String是通过调用this上的toString()方法,于是就发生了递归调用。

如果你真的想要打印出对象的内存地址,应该调用Object.toString()方法,这才是负责任的方法。所以,你不该使用this,而是应该调用super.toString()方法。

正则表达式

正则表达式是一种强大而灵活的文本处理工具。

量词

量词描述了一个模式吸收输入文本的方式:

  • 贪婪型(默认):它的特性是一次性地读入整个字符串,如果不匹配就吐掉最右边的一个字符再匹配,直到找到匹配的字符串或字符串的长度为0为止。它的宗旨是读尽可能多的字符,所以当读到第一个匹配时就立刻返回。
  • 勉强型(在匹配次数的特殊字符后面加一个问号):它的特性是从字符串的左边开始,试图不读入字符串中的字符进行匹配,失败,则多读一个字符,再匹配,如此循环,当找到一个匹配时会返回该匹配的字符串,然后再次进行匹配直到字符串结束。
  • 占有型:它和贪婪模式很相似,不同点是不匹配它不会往回吐字符再匹配。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class RegexMatches
{
public static void main( String args[] ){
// 按指定模式在字符串查找
String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
System.out.println("Found value: " + m.group(3) );
} else {
System.out.println("NO MATCH");
}
}
}

//output
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT
Found value: 3000
Found value: ! OK?
求鼓励,求支持!