Java中的字符串处理

JDK8在线Api中文手册

JDK8在线Api英文手册


   与大多数其他编程语言一样,在Java中,字符串也是一连串的字符。但是,不像其他语言一样作为字符数组实现字符串,Java将字符串实现为String类型的对象。
   作为内置对象实现字符串,使得Java可以提供许多方便字符串处理的特性。例如,Java提供了用于比较两个字符串、查找子串、连接两个字符串以及改变字符串中字母大小写的方法。此外,可以通过多种方式构造String对象,从而当需要时可以很容易地获取字符串。
   当创建String对象时,创建的字符串不能修改。也就是说,一旦创建一个String对象,就不能改变这个字符串中包含的字符。乍一看,这好像有一个严重的限制。但是,情况并非如此。仍然可以执行各种字符串操作。区别是,当每次需要已存在字符串的修改版本时,会创建包含修改后内容的新String对象。原始字符串保持不变。使用这种方式的原因是:实现固定的,不能修改的字符串与实现能修改的字符串相比较效率更高。对于那些需要能够修改的字符串的情况,Java提供了两个选择:StringBuffer和StringBuilder,这两个类用来保存在创建之后可以进行修改的字符串。
   String、StringBuffer、StringBuilder类都是在java.lang中定义的。因此,所有程序自动都可以使用它们。所有这些类被声明为final,这意味着这些类不能有子类。这使得对于通用的字符串操作,可以采取特定的优化以提高性能。这3个类实现了CharSequence接口。
   最后一点,所谓String类型对象中的字符串是不可改变的,是指创建了String实例后不能修改String实例的内容。但是,在任何时候都可以修改String引用变量,使其指向其他String对象。

1.1 String类的构造函数

   String类支持几个构造函数。为了创建空的String,可以调用默认构造函数。例如:

String s = new String();

   将创建内部没有任何字符的String实例。
   经常会希望创建具有初始化值的字符串。String类提供了各种构造函数来解决这个问题。为了创建由字符数组初始化的String实例,可以使用如下所示的构造函数:

String(char chars[])

   下面是一个例子:

char chars[] = {'a','b','c'};
String s = new String(chars);

   这个构造函数使用字符串"abc"初始化s。
   使用下面的构造函数,可以指定字符数组的子范围作为初始化部分:

String(char chars[],int startIndex,int numChars)

   其中,startIndex指定了子范围开始位置的索引,numChars指定了使用的字符数量。下面是一个例子:

char chars[] = {'a','b','c','d','e','f'};
String s = new String(chars,2,3);

   这会使用字符cde初始化s。
   使用下面这个构造函数,可以构造与另外一个String对象包含相同字符的String对象:

String(String strOb)

   在此,strObj是一个String对象。分析下面这个例子:

//Construct one String from another
class MakeString {
 public static void main(String[] args) {
      char c[] ={'J','a','v','a'};
      String s1 = new String(c);
      String s2 = new String(s1);
      System.out.println(s1);
      System.out.println(s2);
      /**
       * 输出:
       * Java
       * Java
       */
  }
}

   可以看出,s1和s2包含相同的字符串。
   尽管Java的char类型使用16位表示基本的Unicode字符集,但是在Internet上,字符串的典型格式是使用从ASCII字符集构造的8位字节数组。因为8位的ASCII字符串很普遍,所以String类提供了使用字节数组初始化字符串的构造函数。下面是其中的两种形式:

String(byte chrs[])
String(byte chrs[],int startIndex,int numChars)

   在此,chrs指定字节数组。上面的第二种形式允许指定子范围。在这两个构造函数中,从字节到字符的转换是使用平台的默认字符编码完成的。下面程序演示了这些构造函数的使用:

//Construct string from subset of char array.
class SubStringCons {
  public static void main(String[] args) {
      byte ascii[]={65,66,67,68,69,70};
      String s1 = new String(ascii);
      System.out.println(s1);
      String s2 = new String(ascii,2,3);
      System.out.println(s2);
      /**
       * 输出
       * ABCDEF
       * CDE
       */
  }
}

   Java还定义了字节到字符串(byte-to-string)构造函数的扩展版本,在扩展版本中可以指定字符的编码方式,这决定了如何将字节转换成字符。但是,通常会希望使用平台提供的默认编码方式。
   注意
   无论何时,从数组创建String对象都会复制数组的内容。在创建字符串之后,如果修改数组的内容,String对象不会发生变化。
   使用下面的构造函数,可以从StringBuffer构造String实例:

String(StringBuffer strBufObj)

   使用下面这个构造函数,可以从StringBuilder构造String实例:

String(StringBulider strBuildObj)

   下面的构造函数支持扩展Unicode字符集:

String(int codePoints[],int startIndex,int numChars)

   其中codePoints是包含Unicode代码点的数组。结果字符串从startIndex开始,截取numChars个字符。
   Java还定义了允许指定Charset的构造函数。

1.2 字符串的长度

   字符串的长度是指字符串所包含字符的数量。为了获取这个值,调用length()方法,如下所示:

int length()
1.3 特殊的字符串操作

   因为字符串在编程中十分常见,也很重要,所以Java语言在语法中为一些字符串操作添加了特殊的支持。这些操作包括从字符串字面值自动创建新的String实例,使用"+"运算符连接多个字符串,以及将其他数据类型转换为字符串表示形式。尽管有显式的方法可以执行这些操作,但是Java可以自动完成这些操作,从而程序员提供便利并增加代码的清晰度。

1.3.1 字符串字面值

   前面的例子显示了如何使用new运算符从字符数组显示地创建String实例。但是,还有更容易的方式,即使用字符串字面值。对于程序中的每个字符串字面值,Java会自动构造String对象。因此,可以使用字符串字面值初始化String对象。例如,下面的代码段创建了两个相等的字符串:

char chars[] = {'a','b','c'};
String s1 = new String(chars);
String s2 = "abc";//use string literal

   因为会为每个字符串字面值创建String对象,所以在能够使用String对象的任何地方都可以使用字符串字面值。例如,可以直接对加引号的字符串调用方法,就好像它们是对象引用一样,如下面的语句所示。下面的代码对字符串"abc"调用length()方法。正如所期望的那样,该语句输出"3"。

System.out.println("abc".length());
1.3.2 字符串连接

   一般而言,Java不允许为String对象应用运算符。这个规则的一个例外是"+“运算符,”+“运算符可连接两个字符串,生成一个String对象作为结果。还可以将一系列”+"运算符连接在一起。例如,下面的代码段连接3个字符串:

String age = "9";
String s = "He is" + age + " years old.";
System.out.println(s);

   上面的代码会显示字符串"He is 9 years old."

1.3.3 字符串和其他数据类型的连接

   可以将字符串和其他类型数据连接起来。例如,分析与前面例子稍微不同的版本。

int age = 9;
String s = "He is" + age + " years old.";
System.out.println(s);

   首先,age是int类型,而不是String类型,但是生成的输出和前面的例子相同。这是因为age中的int值会在String对象中被自动转换成相应的字符串表示形式。然后再像以前那样连接这个字符串。只要"+"运算符的其他操作数是String实例,编译器就会把操作数转换为相应的字符串等价形式。
   但是,当将其他类型的操作和字符串连接表达式混合到一起时,应当小心。可能会得到出乎意料的结果,分析下面的代码:

String s = "four: " + 2 + 2;
System.out.println(s)

   该代码会显示:
   front: 22
   而不是我们可能期望的:
   front: 4
   下面是其中的原因。运算符优先级导致首先连接"four"和2的字符串等价形式,然后再将这个运算的结果和2的字符串等价形式连接起来。为了首先完成整数相加运算,必须使用圆括号,像下面这样:

String s = "four: " + (2 + 2);

   现在s包含字符串"four: 4"

1.3.4 字符串转换和toString()方法

   当Java在执行连接操作期间,将数据转换成相应的字符串表示形式时,是通过调用String定义的字符串转换方式valueOf()的某个重载版本来完成的。valueOf()针对所有基本类型以及Object类型进行了重载。对于基本类型,valueOf()方法返回一个字符串,该字符串包含与调用值等价的人类可以阅读的形式。对于对象,valueOf()方法调用对象的toString()方法。toString()方法决定了所有创建类对象的字符串表示形式。
   每个类都实现了toString()方法,因为该方法是由Object定义的。然而,toString()方法的默认实现很少能够满足需要。对于自己创建的大多数重要类,我们可能希望重写toString()方法并提供自己的字符串表示形式。幸运的是,这很容易完成。toString()方法的一般形式如下:

String toString()

   为了实现toString()方法,可简单地返回一个String对象,使其包含用来描述自定义类对象的人类可阅读的字符串。
   为创建的类重写toString()方法,可以将其完全集成到Java开发环境中。例如,可以把它们用于print()和println()语句,还可以用于字符串连接表达式中。下面的程序通过Box类重写toString()方法,演示了这一点:

//Override toString() for Box class.
class Box {
   double width;
   double height;
   double depth;
   Box(double w, double h, double d) {
       width = w;
       height = h;
       depth = h;
   }
   @Override
   public String toString() {
       return "Dimensions are " + width + " by " + depth + " by " + height + ".";
   }
}
class toStringDemo {
 public static void main(String[] args) {
      Box b = new Box(10, 12, 14);
      String s = "Box b:" + b;//concatenate Box object
      System.out.println(b);//convert Box to string
      System.out.println(s);
      /**
       * 输出:
       * Dimensions are 10.0 by 12.0 by 12.0.
       * Box b:Dimensions are 10.0 by 12.0 by 12.0.
       */
  }
}

   可以看出,在连接表达式或println()调用中使用Box对象时,会自动调用Box的toString()方法。

1.4 提取字符串

   String类提供了大量方法,用于从String对象中提取字符。在此介绍其中的几个。尽管不能向索引数组中的字符那样,索引构成String对象中字符串的字符,但是许多String方法为字符串使用索引(或偏移)来完成它们的操作。和数组一样,字符串索引也是从0开始的。

1.4.1 charAt()

   为了从字符串中提取单个字符,可以通过charAt()方法直接引用某个单个字符。该方法的一般形式如下:

char charAt(int where)

   其中,where是希望获取的字符的索引,where的值必须是非负的,并且能够指定字符串中的一个位置,charAt()方法返回指定位置的字符。例如:

char ch;
ch = "abc".charAt(1);

   将b赋给ch。

1.4.2 getChars()

   如果希望一次提取多个字符,可以使用getChars()方法。它的一般形式为:

void getChars(int sourceStart,int sourceEnd,char target[],int targetStart)

   其中sourceStart指定了子串的开始索引,sourceEnd指定了子串末尾之后下一个字符的索引。因此,子串包含字符串中索引从sourceStart到sourceEnd-1之间的字符。target指定了接收字符的数组。在target中开始复制子串的索引是由targetStart传递的。注意必须确保target数组足够大,以容纳指定子串的字符。

class getCharsDemo {
  public static void main(String[] args) {
       String s = "This is a demo of the getChars method.";
       int start = 10;
       int end = 14;
       char buf[] = new char[end - start];
       s.getChars(start, end, buf, 0);
       System.out.println(buf);
       /**
        * 输出:
        * demo
        */
   }
}
1.4.3 getBytes()

   getChars()的一种替代选择是将字符保存在字节数组中。这个方法是getBytes(),它使用平台提供的从字符到字节转换的默认方法。下面是getBytes()方法最简单的形式:

byte[] getBytes()

   getBytes()方法还有其他形式。当将String值导出到不支持16位Unicode字符的环境中时,最常使用getBytes()方法。例如,大部分Internet协议和文本文件格式为文本交互使用8位ASCII码。

1.4.4 toCharArray()

   如果希望将String对象中的所有字符转换位字符数组,最简单的方法是调用toCharArray()。该方法为整个字符串返回字符数组,它的一般形式如下:

char[] toCharArray()

   这个方法是为了方便操作而提供的,因为可以使用getChars()得到相同的结果。

1.5 比较字符串

   String类提供了大量用来比较字符串或字符串中子串的方法,在此将介绍其中的几个。

1.5.1 equals()和equalsIgnoreCase()

   为了比较两个字符串是否相等,可以使用equals()方法,它的一般形式如下:

boolean equals(Object str)

   其中,str是将要与调用String对象进行比较的String对象。如果字符串以相同的顺序包含相同的字符,该方法返回true,否则返回false。比较是大小写敏感的。
   为了执行忽略大小写区别的比较,可以调用equalsIgnoreCase()。该方法在比较两个字符串时,认为A-Z和a-z是相同的,它的一般形式如下:

boolean equalsIgnoreCase(String str)

   其中,str是将要与调用String对象进行比较的String对象。如果字符串以相同的顺序包含相同的字符,该方法返回true,否则返回false。
   下面是演示equals()和equalsIgnoreCase()的例子:

//Demonstrate equals() and equalsIgnoreCase().
class equalsDemo {
  public static void main(String[] args) {
       String s1 = "Hello";
       String s2 = "Hello";
       String s3 = "Good-bye";
       String s4 = "HELLO";
       System.out.println(s1 + " equals " + s2 + " -> "+s1.equals(s2));
       System.out.println(s1 + " equals " + s3 + " -> "+s1.equals(s3));
       System.out.println(s1 + " equals " + s4 + " -> "+s1.equals(s4));
       System.out.println(s1 + " equalsIgnoreCase " + s4 + " -> "+s1.equalsIgnoreCase(s4));
       /**
        * 输出:
        * Hello equals Hello -> true
        * Hello equals Good-bye -> false
        * Hello equals HELLO -> false
        * Hello equalsIgnoreCase HELLO -> true
        */
   }
}
1.5.2 regionMatches()

   regionMatches()方法比较字符串中某个特定部分与另一个字符串中的另一个特定部分。该方法还有一种重载形式,允许在这种比较中忽略大小写。这个方法的一般形式为:

boolean regionMatches(int startIndex,String str2,int str2StartIndex,int numChars)
boolean regionMatches(boolean ignoreCase,int startIndex,String str2,int str2StartIndex,int numChars)

   对于这两个版本,startIndex指定了调用String对象中比较部分开始的索引位置,,将与之进行比较的String对象是由str2指定的。str2中开始进行比较的索引位置是由str2StartIndex指定的。将要进行比较的子串的长度是由numChars传递的。在第二个版本中,如果ignoreCase为true,那么忽略字符的大小写;否则,大小写就是有意义的。

1.5.3 startsWith()和endsWith()

   String定义了两个方法,它们大体上是regionMatches()方法的特定形式。startsWith()方法确定给定的String对象是否以指定的字符串开始。与之相反,endsWith()方法确定String对象是否以指定的字符串结束。它们的一般形式如下:

boolean startsWith(String str)
boolean endsWith(String str)

   其中,str是将进行测试的String对象。如果字符串匹配,就返回true;否则返回false。例如:

"Foobar".endsWith("bar")

   和

"Foobar".startsWith("Foo")

   都返回true。
   下面是startsWith()方法的第二种形式,这种形式允许指定开始位置:

boolean startsWith(String str,int startIndex)

   其中,startsIndex指定了在调用字符串中要开始查找位置的索引。例如:

"Foobar".startsWith("bar",3)

   返回true。

1.5.4 equals()与==

   equals()方法与“==”运算符执行不同的操作,理解这一点很重要。刚才解释过,equals()方法比较String对象中的字符。双等号运算符比较对两个对象的引用,查看它们是否指向相同的实例。下面的程序演示了两个不同的String对象包含相同字符,但是如果过对这些对象的引用进行比较,就会发现它们是不相等的:

//equals vs ==
class EqualsNotEqualTo {
  public static void main(String[] args) {
       String s1 = "Hello";
       String s2 = new String(s1);
       System.out.println(s1 + " equals " + s2 + " -> " + s1.equals(s2));
       System.out.println(s1 + " == " + s2 + " -> " + (s1 == s2));
       /**
        * 输出:
        * Hello equals Hello -> true
        * Hello == Hello -> false
        */
   }
}

   变量s1引用由"Hello"创建的String实例,s2引用的对象是使用s1作为初始化器创建的。因此,两个String对象的内容是相同的,但它们是不同的对象。这意味着s1和s2引用的是不同的对象,所以不是"=="的关系,正如前面程序的输出所展示的。

1.5.6 compareTo()

   通常,只知道两个字符串是否相同是不够的。对于排序应用,需要知道哪个字符串小于、等于或大于下一个字符串。根据字典顺序,如果一个字符串位于另一个字符串的前面,那么这个字符串小于另一个字符串;如果一个字符串位于另一个字符串的后面,那么这个字符串大于另一个字符串。方法compareTo()就是用于这个目的,该方法是由Comparable<T>接口定义的,String实现了这个接口。compareTo()方法的一般形式如下:

int compareTo(String str)

   其中,str是将要与调用String对象进行比较的String对象。返回的比较结果给及相应解释如下表所示:

compareTo()方法的返回结果
含义
小于0 调用字符串小于str
大于0 调用字符串大于str
0 两个字符串相等

   下面是一个对数组中的字符串进行排序的示例程序。该程序使用compareTo()方法为冒泡排序法确定排列顺序:

//A bubble sort for Strings.
class SortString {
static String arr[] = {"Now", "is", "the", "for", "all",
          "good", "men", "to", "come", "to", "the", "aid"
          , "of", "their", "country"};

  public static void main(String[] args) {
      for (int j = 0; j < arr.length; j++) {
          for (int i = j + 1; i < arr.length; i++) {
              if (arr[i].compareTo(arr[j]) < 0) {
                  String t = arr[j];
                  arr[j] = arr[i];
                  arr[i] = t;
              }
          }
          System.out.println(arr[j]);
      }
      /**
       * 输出:
       * Now
       * aid
       * all
       * come
       * country
       * for
       * good
       * is
       * men
       * of
       * the
       * the
       * their
       * to
       * to
       */
  }
}

   从这个例子的输出可以看出,compareTo()考虑字母的大小写。单词"Now"出现在所有其他单词之前,因为它是以大写字母开头的,这意味着在ASCII字符集中它具有更小的值。
   当比较两个字符串时,如果希望忽略大小写区别,可以使用compareToIgnoreCase(),如下所示:

int compareToIgnoreCase(String str)

   除了忽略大小写外,这个方法的返回结果与compareTo()相同。如果在前面的程序中使用这个方法的话,"Now"将不再是第一个单词。

1.6 查找字符串

   String类提供了两个用于在字符串中查找指定字符或子串的方法:

  • indexOf():查找字符或字符串第一次出现时的索引。
  • lastIndexOf():查找字符和子串最后一次出现时的索引。
       这两个方法都以不同的方式进行了重载。对于所有情况,这些方法都返回发现字符或子串时的索引位置,或返回-1表示查找失败。
       为了查找字符第一次出现时的索引,使用:
int indexOf(int ch)

   为了查找字符最后一次出现时的索引,使用:

int lastIndexOf(int ch)

   其中,ch是将要查找的字符。
   为了查找子串第一次或最后一次出现时的索引,使用:

int indexOf(String str)
int lastIndexOf(String str)

   其中,str指定了将要查找的子串。
   可以使用下面这些形式执行查找开始时的索引:

int indexOf(int ch,int startIndex)
int lastIndexOf(int ch,int startIndex)
int indexOf(String str,int startIndex)
int lastIndexOf(String str,int startIndex)

   其中,startIndex指定了开始查找时的位置索引。对于indexOf(),查找操作从startIndex索引位置运行到字符串的末尾。对于lastIndexOf(),查找操作从startIndex运行到索引位置0。
   下面的例子展示了如何使用各种索引方法在String内部进行查找:

//Demonstrate indexOf() and lastIndexOf().
class indexOfDemo {
 public static void main(String[] args) {
      String s = "Now is the time for all good men "
              + "to come to the aid of their country.";
      System.out.println(s);
      System.out.println("indexOf(t) = " + s.indexOf('t'));
      System.out.println("lastIndexOf(t) = " + s.lastIndexOf('t'));
      System.out.println("indexOf(the) = " + s.indexOf("the"));
      System.out.println("lastIndexOf(the) = " + s.lastIndexOf("the"));
      System.out.println("indexOf(t,10) = " + s.indexOf('t', 10));
      System.out.println("lastIndexOf(t,60) = " + s.lastIndexOf('t', 60));
      System.out.println("indexOf(the,10) = " + s.indexOf("the", 10));
      System.out.println("lastIndexOf(the,60) = " + s.lastIndexOf("the", 60));
      /**
       * 输出:
       *Now is the time for all good men to come to the aid of their country.
       * indexOf(t) = 7
       * lastIndexOf(t) = 65
       * indexOf(the) = 7
       * lastIndexOf(the) = 55
       * indexOf(t,10) = 11
       * lastIndexOf(t,60) = 55
       * indexOf(the,10) = 44
       * lastIndexOf(the,60) = 55
       */
  }
}
1.7 修改字符串

   因为String对象是不可改变的,所以当希望修改String对象时,必须将之复制到StringBuffer或StringBuilder对象中,或者使用String类提供的方法来构造字符串修改后的新副本。下面介绍这些方法中的几个。

1.7.1 substring()

   使用substring方法可以提取子串。它有两种形式,第一种形式如下:

String substring(int startIndex)

   其中,startIndex指定了子串开始时的位置索引。这种形式返回调用字符串中从startIndex索引位置开始到字符串末尾的子串副本。
   substring()方法的第二种形式允许同时指定子串的开始索引和结束索引:

String substring(int startIndex,int endIndex)

   其中,startIndex指定开始索引,endIndex指定结束索引。返回的字符串包含从开始索引到结束索引的字符,但是不包含结束索引位置的字符
   下面的程序使用substring()方法在一个字符串中使用一个字符串替换另一个子串的所有实例:

//Substring replacement.
class StringReplace {
  public static void main(String[] args) {
       String org = "This is a test. This is, too.";
       String search = "is";
       String sub = "was";
       String result = "";
       int i;
       do {//replace all matching substrings
           System.out.println(org);
           i = org.indexOf(search);
           if (i != -1) {
               result = org.substring(0, i);
               result = result + sub;
               result = result + org.substring(i + search.length());
               org = result;
           }
       } while (i != -1);
       /**
        * This is a test. This is, too.
        * Thwas is a test. This is, too.
        * Thwas was a test. This is, too.
        * Thwas was a test. Thwas is, too.
        * Thwas was a test. Thwas was, too.
        */
   }
}
1.7.2 concat()

   可以使用concat()方法来连接两个字符串,如下所示:

String concat(String str)

   该方法创建一个新对象,这个新对象包含调用字符串并将str的内容追加到结尾。concat()与"+"执行相同的功能。例如:

String s1 = "one";
String s2 = s1.concat("two");

   将字符串"onetwo"存放发s2中。与下面语句产生的结果相同:

String s1 = "one";
String s2 = s1 + "two";
1.7.3 replace()

   replace()方法有两种形式。第一种形式在调用字符串中使用一个字符代替另一个字符的所有实例,一般形式如下:

String replace(char original,char replacement)

   其中,original指定将被替换的字符,replacement指定替换字符,结果字符串将被返回。例如:

String s = "Hello".replace('1','w')

   将字符串"Hewwo"存放到s中。
   replace()方法的第二种形式使用一个字符序列代替另一个字符序列,一般形式如下:

String replace(CharSequence original,CharSequence replacement)
1.7.4 trim()

   trim()方法返回调用字符串的副本,并移除开头和结尾的所有空白字符,一般形式如下:

String trim()

   下面是一个例子:

String s = " Hello World ".trim();

   这条语句将字符创"Hello World"存放到s中。
   当处理用户命令时,trim()方法特别有用。例如,下面的程序用户输入某个州的名称,然后显示该州的首府。该程序使用trim()方法移除用户可能无意中输入的开头和结尾的所有空白字符。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

//Using trim() to process commands.
class UserTrim {
 public static void main(String[] args) throws IOException {
      //create a BufferedReader using System.in
      BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
      String str;
      System.out.println("Enter 'stop' to quit.");
      System.out.println("Enter State: ");
      do {
          str = br.readLine();
          str = str.trim();//remove whitespace
          if (str.equals("Illinois"))
              System.out.println("Capital is Springfield.");
          else if (str.equals("Missouri"))
              System.out.println("Capital is Jefferson City");
          else if (str.equals("California"))
              System.out.println("Capital is Sacramento.");
          //...
      } while (!str.equals("stop"));
  }
}
1.8 使用valueOf()转换数据

   valueOf()方法将数据从内部格式转换成人类可以阅读的形式。valueOf()是静态方法,String针对所有Java内置类型对该方法进行了重载,从而可以将每种类型正确地转换成字符串。Java还针对Object类型对valueOf()方法进行了重载,从而使您创建的所有类类型的对象都可作为valueOf()方法的参数(Object是所有类的超类)。下面是valueOf()方法的几种形式:

static String valueOf(double num)
static String valueOf(long num)
static String valueOf(Object ob)
static String valueOf(char chars[])

   前面讨论过,当需要其他类型数据的字符串表示形式时会调用valueOf()方法,例如在连接操作期间。可以使用任何数据类型直接调用valueOf()方法,从而得到可读的字符串表示形式。所有简单类型都被转换成它们通用的字符串表示形式。传递给valueOf()方法的所有对象都将返回调用对象的toString()方法的结果。实际上,可以直接调用toString()方法得到相同的结果。
   对于大部分数组,valueOf()方法会返回一个相当隐蔽的字符串,以表明这是某种类型的数组。然而,对于字符数组,会创建包含字符数组的String对象。还有一个特殊版本的valueOf()方法,允许指定字符数组的子集,一般形式为:

static String valueOf(char chars[],int startIndex,int numChars)

   其中,chars是包含字符的数组,startIndex是期望子串在字符数组中何处开始的位置索引,numChars指定了子串的长度。

1.9 改变字符串中字符的大小写

   方法toLowerCase()将字符串中的所有字符从大写改变为小写,方法toUpperCase()将字符串中的所有字符从小写改为大写。非字母字符不受影响。下面是这些方法的最简单形式:

String toLowerCase()
String toUpperCase()

   这些方法返回String对象,其中包含与调用字符串等价的大写或小写形式。对于这两种情况下,都是由默认区域设置控制转换。

//Demonstrate toUpperCase() and toLowerCase().
class ChangeCase {
  public static void main(String[] args) {
       String s = "This is a test.";
       System.out.println("Original: " + s);
       String upper = s.toUpperCase();
       String lower = s.toLowerCase();
       System.out.println("UpperCase: " + upper);
       System.out.println("LowerCase: " + lower);
       /**
        * 输出:
        * Original: This is a test.
        * UpperCase: THIS IS A TEST.
        * LowerCase: this is a test.
        */
   }
}

   另外一点:toLowerCase()和toUpperCase()方法的重载版本,还允许指定控制转换的Locale对象。对于某些情况,指定区域非常重要,和有助于国际化应用程序

1.10 连接字符串

   JDK 8 为String类添加了一个新方法join(),用于连接两个或更多个字符串,并使用分隔符分隔各个字符串,如空格或逗号。join()方法有两种形式,第一种形式如下所示:

static String join(CharSequence delim,CharSequence ...strs)

   其中,delim指定了分隔符,用于分隔strs指定的字符序列。因为String类实现了CharSequence接口,所以strs可以是一个字符串列表,下面的程序演示了这个版本的join()方法:

//Demonstrate the join() method defined by String.
class StringJoinDemo {
  public static void main(String[] args) {
       String result = String.join(" ", "Alpha", "Beta", "Gamma");
       System.out.println(result);
       result = String.join(", ", "John", "ID#: 569",
               "E-mail: [email protected]");
       System.out.println(result);
       /**
        * 输出:
        * Alpha Beta Gamma
        * John, ID#: 569, E-mail: [email protected]
        */
   }
}

   第一次调用join()时,在每个字符串之间插入了空格。在第二次调时,指定分隔符为一个逗号加一个空格,这表明分隔符并非只能是一个字符。
   join()方法的第二种形式允许连接从实现了Iterable接口的对象获取的一个字符串列表。

1.11 其他String方法

   除了前面讨论的方法外,String类还提供了许多其他方法。如下表所示:

String类的其他方法
方法 描述
int codePointAt(int i) 返回由i指定的位置的Unicode代码点
int codePointBefore(int i) 返回由i指定的位置之前的Unicode代码点
int codePointCount(int start,int end) 返回调用字符串处于start到end-1索引范围内的代码代码点数
boolean contains(CharSequence str) 如果调用字符串包含由str指定的字符串,就返回true;否则返回false
boolean contentEquals(CharSequence str) 如果调用字符串和str包含的字符串相同,就返回true;否则返回false
boolean contentEquals(StringBuffer str) 如果字符串和str包含的字符串相同,就返回true;否则返回false
static String format(String fmtstr,Object …args) 返回格式化的字符串,由fmtstr指定
static String format(Locale loc,String fmtstr,Object …args) 返回格式化的字符串,由fmtstr指定。格式化是由loc指定的区域控制的
boolean isEmpty() 如果调用字符串没有任何字符并且长度为0,就返回true
boolean matches(String regExp) 如果调用字符串和regExp传递的正则表达式匹配,就返回true;否则返回false
int offsetByCodePoints(int start,int num) 返回字符串中超过start所指定开始索引num个代码点的索引
String replaceFirst(String regExp,String newStr) 返回一个字符串,在返回的这个字符串中,使用newStr替换与regExp所指定正则表达式匹配的第一个子串
String replaceAll(String regExp,String newStr) 返回一个字符串,在返回的这个字符串中,使用newStr替换与regExp所指定正在表达式匹配的所有子串
String[] split(String regExp) 将调用字符串分解成几个部分,并返回包含结果的数组。每一部分都由regExp传递的正则表达式进行界定
String[] split(String regExp,int max) 将调用字符串分解成几个部分,并返回包含结果的数组。每一部分都由regExp传递的正则表达式进行界定。max指定分解的块数。如果max是 负数,就完全分解调用字符串。否则,如果max包含非零值,那么结果数组中的最后一个元素是调用字符串的剩余部分。如果max是0,就完全分解调用字符串,但是不会包含后跟的空字符串
CharSequence subSequence(int startIndex,int stopIndex) 返回调用字符串的子串,从startIndex索引位置开始,并在stopIndex索引位置结束。该方法是CharSequence接口所需要的,String类实现了CharSequence接口

   注意这些方法中的多个都使用正则表达式进行工作。

1.12 StringBuffer类

   StringBuffer支持可修改的字符串。我们知道,String表示长度固定、不可修改的字符序列。与之相对应,StringBuffer表示可增长、可写入的字符序列。StringBuffer允许在中间插入字符和子串,或者在末尾追加字符和子串。StringBuffer能够自动增长,从而为这类添加操作准备空间,并且通常预先分配比实际需要更多的字符空间,以允许空间增长。

1.12.1 StringBuffer类的构造函数

   StringBuffer类定义了以下4个构造函数:

StringBuffer()
StringBuffer(int size)
StringBuffer(String str)
StringBuffer(CharSequence chars)

   默认构造函数(没有参数的那个)预留16个字符的空间,不需要再分配。第2个版本接收一个显式设置缓冲区大小的整型参数。第3个版本接收一个设置StringBuffer对象初始化内容的String参数,并额外预留16个字符的空间,不需要再分配。如果没有要求特定的缓冲区长度,StringBuffer会为16个附加字符分配空间,因为再次分配空间是很耗时的操作。此外,频繁分配空间会产生内存碎片。通过为一部分额外字符分配空间,StringBuffer减少了再次分配空间的次数。第4个构造函数创建包含字符序列的对象,并额外预留16个字符的空间,包含的字符序列是由chars指定的。

1.12.2 length() 与 capacity()

   通过length()方法可以获得StringBuffer对象的当前长度,而通过capacity()方法可以获得已分配的容量。这两个方法的一般形式如下:

int length()
int capacity()

   下面是一个例子:

//StringBuffer length vs capacity
class StringBufferDemo {
  public static void main(String[] args) {
       StringBuffer sb = new StringBuffer("Hello");
       System.out.println("buffer = "+sb);
       System.out.println("length = "+sb.length());
       System.out.println("capacity = "+sb.capacity());
       /**
        * 输出:
        * buffer = Hello
        * length = 5
        * capacity = 21
        */
   }
}

   因为sb在创建时是使用字符串"Hello"初始化的,所以它的长度是5。因为自动添加了16个附加字符的空间,所以它的容量是21。

1.12.3 ensureCapacity()

   在创建了StringBuffer对象后,如果希望为特定数量的字符预先分配空间,可以使用ensureCapacity()方法设置缓冲区的大小。如果事先知道将要向StringBuffer对象追加大量的小字符串,这个方法是有用的。ensureCapacity()方法的一般形式为:

void ensureCapacity(int minCapacity)

   其中,minCapacity指定了缓冲区的最小尺寸(处于效率方面的考虑,可能会分配比minCapacity更大的缓存区)。

1.12.4 setLength()

   可以使用setLength()方法设置StringBuffer中字符串的长度,一般形式为:

void setLength(int len)

   其中,len指定字符串的长度,值必须非负。
   当增加字符串的大小时,会向末尾添加null字符。如果调用setLength()方法时,使用的值小于length()方法返回的当前值,那么超出新长度的字符将丢失。

1.12.5 charAt() 与 setCharAt()

   通过charAt()方法可以从StringBuffer获取单个字符的值,使用setCharAt()方法可以设置StringBuffer对象中某个字符的值。这两个方法的一般形式如下所示:

char charAt(int where)
void setCharAt(int where,char ch)

   对于charAt()方法,where指定了将要获取字符的索引。对于setCharAt()方法,where指定了将要设置字符的索引,ch指定了字符的新值。对于这两个方法,where必须是非负的,并且不能超出字符串结尾的位置。下一节中的setCharAtDemo示例程序使用setLength()方法缩短了一个StringBuffer对象。
   下面的例子演示了charAt()和setCharAt()方法:

//Demonstrate charAt() and setCharAt()
class setCharAtDemo {
  public static void main(String[] args) {
      StringBuffer sb = new StringBuffer("Hello");
      System.out.println("buffer before = "+sb);
      System.out.println("charAt(1) before = "+sb.charAt(1));
      sb.setCharAt(1,'i');
      System.out.println("setCharAt after = "+sb);
      sb.setLength(2);
      System.out.println("buffer after = "+sb);
      System.out.println("CharAt(1) after = "+sb.charAt(1));
      /**
       * 输出:
       * buffer before = Hello
       * charAt(1) before = e
       * setCharAt after = Hillo
       * buffer after = Hi
       * CharAt(1) after = i
       */
  }
}
1.12.6 getChars()

   可以使用getChars()方法将StringBuffer对象的子串复制到数组中,一般形式为:

void getChars(int sourceStart,int sourceEnd,char target[],int targetStart)

   其中,sourceStart指定了子串开始位置的索引,sourceEnd指定子串结束位置的最后一个位置的索引。这意味着子串将包含索引位置从sourceStart到sourceEnd-1之间的字符。接收字符的数组是由target指定的。targetStart指定了在target中开始复制子串的位置索引。用getChars()方法是一定要谨慎,确保target足以容纳子串中的字符。

1.12.7 append()

   append()方法将各种其他类型数据的字符串表示形式连接到调用StringBuffer对象的末尾。该方法有一些重载版本,下面是其中的几个:

StringBuffer append(String str)
StringBuffer append(int num)
StringBuffer append(Object obj)

   通常调用String.valueOf()来获取每个参数的字符串表示形式,结果将被添加到当前StringBuffer对象的末尾。缓冲区本身被各种版本的append()方法返回,从而可以将一系列调用连接起来,如下面的例子所示:

//Demonstrate append().
class appendDemo {
  public static void main(String[] args) {
       String s;
       int a = 42;
       StringBuffer sb = new StringBuffer(40);
       s= sb.append("a = ").append(a).append("!").toString();
       System.out.println(s);
       /**
        * 输出:
        * a = 42!
        */
   }
}
1.12.8 insert()

   insert()方法将一个字符串插入到另一个字符串中。Java对该方法进行了重载,以接收所有基本类型以及String、Object和CharSequence类型的值。与append()类似,该方法获取参数值的字符串表示形式,然后将字符串插入到调用StringBuffer对象中。下面是其中的几种重载形式:

StringBuffer insert(int index,String str)
StringBuffer insert(int index,char ch)
StringBuffer insert(int index,Object obj)

   其中,index指定了字符串插入到调用StringBuffer对象的位置索引。
   下面的示例程序将"like"插入到"I"和"Java"之间:

//Demonstrate insert()
class insertDemo {
  public static void main(String[] args) {
       StringBuffer sb = new StringBuffer("I Java!");
       sb.insert(2,"like ");
       System.out.println(sb);
       /**
        * 输出:
        * I like Java!
        */
   }
}
1.12.9 reverse()

   可以使用reverse()方法颠倒StringBuffer对象中的字符,如下所示:

StringBuffer reverse()

   该方法返回对象的反转形式。下面的程序演示了reverse()方法:

//Using reverse() to reverse a StringBuffer
class ReverseDemo {
  public static void main(String[] args) {
       StringBuffer s = new StringBuffer("abcdef");
       System.out.println(s);
       s.reverse();
       System.out.println(s);
       /**
        * 输出:
        *abcdef
        *fedcba
        */
   }
}
1.12.10 delete() 与 deleteCharAt()

   使用delete()和deleteCharAt()方法可以删除StringBuffer对象中的字符。写方法如下所示:

StringBuffer delete(int startIndex,int endIndex)
StringBuffer deleteCharAt(int loc)

   delete()方法从调用对象删除一连串字符。其中,startIndex指定第一个删除字符的位置索引,endIndex指定要删除的最后一个字符之后的下一个字符的位置索引。因此,结果是删除索引位置从startIndex到endIndex-1之间的子串。删除字符串后的StringBuffer对象作为结果返回。
   deleteCharAt()方法删除由loc指定的索引位置的字符,返回删除字符后的StringBuffer对象。
   下面是演示delete()和deleteCharAt()方法的程序:

//Demonstrate delete() and deleteCharAt()
class deleteDemo {
  public static void main(String[] args) {
       StringBuffer sb = new StringBuffer("This is a test.");
       sb.delete(4,7);
       System.out.println("After delete: "+sb);
       sb.deleteCharAt(0);
       System.out.println("After deleteCharAt: "+sb);
       /**
        * 输出:
        * After delete: This a test.
        * After deleteCharAt: his a test.
        */
   }
}
1.12.11 replace()

   通过调用replace()方法可以使用一个字符集替换StringBuffer对象中的另一个字符集。该方法的签名如下所示:

StringBuffer replace(int startIndex,int endIndex,String str)

   索引startIndex和endIndex指定了将被替换的子串,因此将替换startIndex和endIndex-1索引位置之间的子串。替换字符串是由str传入的。替换后的StringBuffer对象作为结果返回。
   下面的程序演示了replace()方法:

//Demonstrate replace()
class replaceDemo {
  public static void main(String[] args) {
       StringBuffer sb = new StringBuffer("This is a test.");
       sb.replace(5,7,"was");
       System.out.println("After replace: "+sb);
       /**
        * 输出:
        * After replace: This was a test.
        */
   }
}
1.12.12 substring()

   通过调用substring()方法可以获得StringBuffer对象的一部分。该方法有以下两种重载形式:

String substring(int startIndex)
String substring(int startIndex,int endIndex)

   第一种形式返回从索引位置startIndex开始到调用StringBuffer对象末尾之间的子串,第二种形式返回startIndex和endIndex-1索引位置之间的子串。这些方法的工作方式与前面介绍的String类的对应方法类似。

1.12.13 其他StringBuffer方法

   除了刚才介绍的方法外,StringBuffer还提供了其他一些方法,如下表所示:

StringBuffer的其他一些方法
方法 描述
StringBuffer appendCodePoint(int ch) 在调用对象的末尾添加一个Unicode代码点,返回对调用对象的引用
int codePointAt(int i) 返回由i指定的位置的Unicode代码点
int codePointBefore(int i) 返回由i指定的位置之前位置的Unicode代码点
int codePointCount(int start,int end) 返回调用对象在位置start和end-1之间代码点的数量
int indexOf(String str) 查找str在调用StringBuffer对象中的第一次出现时的位置索引,并返回索引。如果没有找到,就返回-1
int indexOf(String str,int startIndex) 从startIndex位置索引开始查找查找str在StringBuffer对象中第一次出现时的位置索引,并返回索引。如果没有找到,就返回-1
int lastIndexOf(String str) 查找str在调用StringBuffer对象中最后一次出现时的位置索引,并返回该索引。如果没有找到,就返回-1
int lastIndexOf(String str,int startIndex) 从位置索引startIndex开始查找str在StringBuffer对象中最后一次出现时的位置索引,并返回该索引。如果没有找到,就返回-1
int offsetByCodePoints(int start,int num) 返回调用字符串中超过start所指定索引位置num个代码点的索引
CharSequence subSequence(int startIndex,int stopIndex) 返回调用字符串的一个子串,从位置索引startIndex开始,到stopIndex位置索引结束。这个方法是CharSequence接口所需要的,StringBuffer实现了该接口
void trimToSize() 要求为调用对象减小字符缓存对的大小,以更适合当前内容

   下面的程序演示了indexOf()方法和lastIndexOf()方法:

//下面的程序演示了indexOf()方法和lastIndexOf()方法:
class IndexOfDemo {
  public static void main(String[] args) {
       StringBuffer sb = new StringBuffer("one two one");
       int i;
       i = sb.indexOf("one");
       System.out.println("First index: "+i);
       i = sb.lastIndexOf("one");
       System.out.println("Last index: "+i);
       /**
        * 输出:
        * First index: 0
        * Last index: 8
        */
   }
}
1.13 StringBuilder类

   StringBuilder类是由JDK5引入的,以增强Java的字符串处理能力。StringBuilder与StringBuffer类似,只有一个重要的区别:StringBuilder不是同步的,这意味着它不是线程安全的。StringBuilder的优势在于能得到更高的性能。但是,如果可以修改的字符串将被多个线程修改,并且没有其他同步措施的话,就必须使用StringBuffer,而不能使用StringBuilder。

发布了59 篇原创文章 · 获赞 20 · 访问量 3641

猜你喜欢

转载自blog.csdn.net/qq_34896730/article/details/103751782