Java编程思想10——String

1.不可变String

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

对千一个方法而言, 参数是为该方法提供信息的, 而不是想让该方法改变自己的。

2.重载+与StringBuilder

用千String的"+"与"+=" 是Java中仅有的两个重载过的操作符,而Java井不允许程序员重载任何操作符。

如果拿不准该用哪种方式,随时可以用javap来分析你的程序。
StringBuilder是JavaSE5引人的,在这之前Java用的是StringBuffer。后者是线程安全的,因此开销也会大些,所以在JavaSE5/6中,字符串操作应该还会更快一点。

3.无意识的递归

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

public class InfiniteRecursion { 
  public String toString() { 
    return " InfiniteRecursion address: " + this + "\n": 
  }

这里发生了自动类型转换,由InfiniteRecursion类型转换成String类型。因为编译器看到一个String对象后面跟着一个"+"'而再后面的对象不是String,于是编译器试渚将this转换成一个String。它怎么转换呢,正是通过调用this上的toString()方法,千是就发生了递归调用。

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

4.String上的操作

当需要改变字符串的内容时,String类的方法都会返回一个新的 String对象。同时,如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。这 可以节约存储空间以及避免额外的开销。

5.格式化输出

5.1 printf()

5.2 System.out.format()

format()与printf()是等价的。

5.3 Formatter类

在Java中,所有新的格式化功能都由java.util.Formatter类处理。可以将Formatte看作一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。当你创建一个Formatter对象的时候, 需要向其构造器传递一些信息,告诉它最终的结果将向哪里输出。

5.4 格式化说明符

%[argument_index$] [flags] [width][.precision]conversion 

最常见的应用是控制一个域的最小尺寸,这可以通过指定width来实现。 Formatter对象 通过在必要时添加空格,来确保一个域至少达到某个长度。 在默认的情况下,数据是右对齐,不过可以通过使用"-"标志来改变对齐方向。
与width相对的是precision, 它用来指明最大尺寸。width可以应用于各种类型的数据转换, 并且其行为方式都一样。 precision则不然, 不是所有类型的数据都能使用precision, 而且,应用于不同类型的数据转换时,precision的意义也不同。 在将precision应用于String时,它表示打印 String时输出字符的最大数址。 而在将precision应用千浮点数时, 它表示小数部分要显示出来的位数(默认是6位小数), 如果小数位数过多则舍人, 太少则在尾部补零。 由千整数没有小数部分,所以precision无法应用千整数,如果你对整数应用precision, 则会触发异常。

5.5 Formatter转换

5.6 String.format()

String.format()是一个 static方法,它接受与Formatter.format()方法一样的参数,但返回一个String对象。当你只需使回用format()方法一次的时候,String.format()用起来很方便。

其实在String.format()内部,它也是创建一个Formatter对象,然后将你传人的参数转给该Formatter。

6.正则表达式

正则表达式提供了一种完全通用的方式,能够解决各种字符串处理相关的问题:匹配、选择、编辑以及验证。

6.1 基础

在Java中,\的意思是“我要插人一个正则表达式的反斜线,所以其后的字符具有特殊的意义。例如,如果你想表示一位数字,那么正则表达式应该是\d。如果你想插人一个普通的反斜线,则应该这样\\。不过换行和制表符之类的东西只需使用单反斜线:\n\t。

在正则表达式中,括号有着将表达式分组的效果,而竖直线|则表示或操作。

String类还自带了一个非常有用的正则表达式工具--split()方法,其功能是“将字符串从正则表达式匹配的地方切开。”

6.2 创建正则表达式

完整请参考java.util.regex.Pattern

6.3 量词

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

  • 贪婪型:量词总是贪婪的,除非有其他的选项被设置。 贪婪表达式会为所有可能的模式发现尽可能多的匹配。 导致此问题的一个典型理由就是假定我们的模式仅能匹配第一个可能的字符组,如果它是贪婪的,那么它就会继续往下匹配。
  • 勉强型:用问号来指定, 这个址词匹配满足模式所需的最少字符数。 因此也称作懒惰的、 最少匹配的、 非贪婪的、 或不贪婪的。
  • 占有型:目前, 这种类型的懋词只有在Java语言中才可用(在其他语言中不可用),井且也更高级,因此我们大概不会立刻用到它。 当正则表达式被应用于字符串时,它会产生相当多的状态, 以便在匹配失败时可以回溯。 而 “占有的“ 址词并不保存这些中间状态, 因此它们可以防止回溯。 它们常常用千防止正则表达式失控,因此可以使正则表达式执行起来更有效。

多数正则表达式操作都接受CharSequence类型的参数。

6.4 Pattern和Matcher

一般来说,比起功能有限的String类,我们更愿意构造功能强大的正则表达式对象。只需导人Java.util.regex包,然后用staticPattern.compile()方法来编译你的正则表达式即可。它会根据你的String类型的正则表达式生成一个Pattern对象。接下来,把你想要检索的字符串传人 Pattern对象的matcher()方法。matcher()方法会生成一个Matcher对象,它有很多功能可用。
Matcher

组(Groups)
组是用括号划分的正则表达式,可以根据组的编号来引用某个组。组号为0表示整个表达式, 组号1表示被第一对括号括起的组, 依此类推。

6.5 split()

split()方法将输入字符串断开成字符串对象数组。

6.6 替换操作

正则表达式特别便千替换文本,它提供了许多方法:replaceFirst(String replacement)以参 数字符串replacemen氓换掉第一个匹配成功的部分。replaceAll(Stringreplacement)以参数字符串replacement替换所有匹配成功的部分。appendReplacement(StringBuffersbuf, String replacement)执行渐进式的替换,而不是像replaceFirst()和replaceAII()那样只替换第一个匹配或全部匹配。

6.7 reset()

通过reset()方法,可以将现有的Matcher对象应用千一个新的字符序列。

6.8 正则表达式与Java I/O

7.扫描输入

到目前为止,从文件或标准输人读取数据还是一件相当痛苦的事情。一般的解决之道就是读入读入一行文本,对其进行分词,然后使用Integer、Double等类的各种解析方法来解析数据。

Java SE5新增了Scanner类, 它可以大大减轻扫描输入的工作负担。

7.1 Scanner定界符

默认是空白字符,但是可以通过正则表达式指定自己所需的定界符。

7.2 用正则表达式扫描

除了能够扫描基本类型之外,你还可以使用自定义的正则表达式进行扫描,这在扫描复杂数据的时候非常有用。

8.StringTokenizer

在Java引入正则表达式和Scanner类之前,分割字符串的唯一方法是使用StringTokenizer来分词。 不过,现在有了正则表达式和Scanner, 我们可以使用更加简单、更加简洁的方式来完成同样的工作了。

你可能感兴趣的:(Java编程思想10——String)