特殊的String

A Brief Summary of String Class

一个String对象是一个unicode字符序列.在C和C++中,string仅仅是一个字符数组(标准C++定义了string类),Java的String是核心包java.lang中的一个对象类。

与普通class不同之处表现在:

  • 除了调用String的构造方法之外,还可以这样创建String对象:String s1 = new String("Hello");
  • 重载了‘+’运算符来连接两个字符串
  • String是不可变的,意识是,当String类被创建之后,其内容是不能被更改的。例如,它的toUpperCase()并不会在String对象内容上作出改变,而是会构造并返回一个新的String对象。

String类中的常用方法:

// Length
int length()       // returns the length of the String
boolean isEmpty()  // same as thisString.length == 0
 
// Comparison
boolean equals(String another) // CANNOT use '==' or '!=' to compare two Strings
boolean equalsIgnoreCase(String another)
int compareTo(String another)  // return 0 if this string is the same as another;
                               // <0 if lexicographically less than another; or >0
int compareToIgnoreCase(String another)
boolean startsWith(String another)
boolean startsWith(String another, int fromIndex)  // search begins at fromIndex
boolean endsWith(String another)
 
// Searching & Indexing
int indexOf(String search)
int indexOf(String search, int fromIndex)
int indexOf(int character)
int indexOf(int character, int fromIndex)      // search forward starting at fromIndex
int lastIndexOf(String search)
int lastIndexOf(String search, int fromIndex)  // search backward starting at fromIndex
int lastIndexOf(int character)
int lastIndexOf(int character, int fromIndex)
 
// Extracting character or part of the String
char charAt(int index)              // index from 0 to String's length - 1
String substring(int fromIndex)
String substring(int fromIndex, int endIndex)  // exclude endIndex
 
// Creating a new String or char[] from the original (Strings are immutable!)
String toLowerCase()
String toUpperCase()
String trim()          // create a new String removing white spaces from front and back
String replace(char oldChar, char newChar)  // create a new String with oldChar replaced by newChar
String concat(String another)               // same as thisString + another
char[] toCharArray()                        // create a char[] from this string
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)  // copy into dst char[]
 
// Static methods for converting primitives to String
static String ValueOf(type arg)  // type can be primitives or char[]
 
// Static method resulted in a formatted String using format specifiers
static String format(String formattingString, Object... args)   // same as printf()
 
// Regular Expression (JDK 1.4)
boolean matches(String regexe)
String replaceAll(String regexe, String replacement)
String replaceAll(String regexe, String replacement)
String[] split(String regexe)             // Split the String using regexe as delimiter,
                                          // return a String array
String[] split(String regexe, int count)  // for count times only

String确实很特殊

在Java中,String享受到了“特殊待遇”,因为它的使用实在是太频繁。因此,效率(而不是计算和存储)是至关重要的。

为了提高Java的性能,Java的设计者们保留了在。这样一种面向对象语言中保留了基本数据类型。

基本数据保存在栈中,占用的空间资源少而且操作效率高;而对象保存在程序堆中,需要进行复杂的内存管理,且需要的空间资源更多。

考虑到性能问题,Java的String被设计成介乎基本数据类型与类类型之间。其特殊性体现在:

  • ‘+’操作符。‘+’操作符是基本数据类型时间的运算,String重载该运算符用来拼接两个字符串(译者注:这是Java唯一实现了运算符重载的地方);
  • 除了调用String的构造方法之外,还可以这样创建String对象:String s1 = new String("Hello");

  • String str1 = "Java is Hot";           // Implicit construction via string literal
    String str2 = new String("I'm cool");  // Explicit construction via new 
  • 第一行代码中,str1被声明为一个String引用并通过一个字符串“Java is Hot”来进行初始化;在第二句代码中,str2被声明为一个String引用并通过new操作创建一个内容为“I'm cool”的对象进行初始化。

  • 字符串存储在常量池中。这有便于内容相同的字符串的存储,以节省空间。通过new操作符创建的String对象存储在堆中,且不存在共享机制。
String Literal vs. String Object

正如所提到的,存在两种方式创建String对象:通过“ ”隐式创建或者通过new操作符显示创建。例如:

String s1 = "Hello";              // String literal
String s2 = "Hello";              // String literal
String s3 = s1;                   // same reference
String s4 = new String("Hello");  // String object
String s5 = new String("Hello");  // String object

Java has designed a special mechanism for keeping theString literals - in a so-calledstring common pool. If twoString literals have the same contents, they will share the same storage locations inside the common pool. This approach is adopted toconserve storage for frequently-used strings. On the other hands,String object created via thenew operator are kept in the heap. EachString object in the heap has its own storage just like any other object. There is no sharing of storage in heap even if twoString objects have the same contents.

You can use the method equals() of theString class to compare the contents of twoStrings. You can use the relational equality operator'==' to compare the references (or pointers) of two objects. Study the following codes:

s1 == s1;         // true, same pointer
s1 == s2;         // true, s1 and s1 share storage in common pool
s1 == s3;         // true, s3 is assigned same pointer as s1
s1.equals(s3);    // true, same contents
s1 == s4;         // false, different pointers
s1.equals(s4);    // true, same contents
s4 == s5;         // false, different pointers in heap
s4.equals(s5);    // true, same contents

Important Notes:

  • In the above example, I used relational equality operator'==' to compare the references of twoString objects. This is done to demonstrate the differences betweenString literals sharing storage in the common pool andString objects created in the heap. It is alogical error to use(str1 == str2) in your program forcomparing the contents of twoStrings.
  • String can be created by directly assigning aString literal which is shared in a common pool. It is uncommon and not recommended to use the new operator to construct aString object in the heap.

[TODO] Explain the method String.intern().

String is Immutable

Since String literals with the same contents share storage in the common pool, Java'sString isimmutable. That is, once aString is constructed, its contents cannot be modified. Otherwise, the otherString references sharing the same storage location will be affected by the change, which can be unpredictable and therefore is undesirable. Methods such astoUpperCase() might appear to modify the contents of aString object. In fact, a completely newString object is created and returned to the caller. The originalString object will be deallocated, once there is no more references, and subsequently garbage-collected.

Because String is immutable, it is not efficient to useString if you need to modify your string frequently (that would create many newStrings occupying new storage areas). For example,

// inefficient codes
String str = "Hello";
for (int i = 1; i < 1000; i++) {
   str = str + i;
}

If the contents of a String have to be modified frequently, use theStringBuffer orStringBuilder class instead.

StringBuffer and StringBuilder

As explained earlier, Strings areimmutable becauseString literals with same content share the same storage in the string common pool. Modifying the content of oneString directly may cause adverse side-effects to otherStrings sharing the same storage.

JDK provides two classes to support mutable strings: StringBuffer and StringBuilder (in core packagejava.lang) . AStringBuffer orStringBuilder object is just like any ordinary object, which are stored in the heap and not shared, and therefore, can be modified without causing adverse side-effect to other objects.

StringBuilder class was introduced in JDK 1.5. It is the same asStringBuffer class, except thatStringBuilder isnot synchronized for multi-thread operations. However, for single-thread program,StringBuilder, without the synchronization overhead, is more efficient.

StringBuffer

Read the JDK API specification for java.lang.StringBuffer.

// Constructors
StringBuffer()             // an initially-empty StringBuffer
StringBuffer(int size)     // with the specified initial size
StringBuffer(String s)     // with the specified initial content
 
// Length
int length()
 
// Methods for building up the content
StringBuffer append(type arg)  // type could be primitives, char[], String, StringBuffer, etc
StringBuffer insert(int offset, arg)
 
// Methods for manipulating the content
StringBuffer delete(int start, int end)
StringBuffer deleteCharAt(int index)
void setLength(int newSize)
void setCharAt(int index, char newChar)
StringBuffer replace(int start, int end, String s)
StringBuffer reverse()
 
// Methods for extracting whole/part of the content
char charAt(int index)
String substring(int start)
String substring(int start, int end)
String toString()
 
// Methods for searching
int indexOf(String searchKey)
int indexOf(String searchKey, int fromIndex)
int lastIndexOf(String searchKey)
int lastIndexOf(String searchKey, int fromIndex)


Take note that StringBuffer is an ordinary object. You need to use a constructor to create aStringBuffer (instead of assigning to a String literal). Furthermore,'+' operator does not apply to objects, inclusive of StringBuffer. You need to use a proper method such asappend() or insert() to manipulating a StringBuffer.

To create a string from parts, It is more efficient to useStringBuffer (multi-thread) orStringBuilder (single-thread) instead of viaString concatenation. For example,

// Create a string of YYYY-MM-DD HH:MM:SS
int year = 2010, month = 10, day = 10;
int hour = 10, minute = 10, second = 10;
String dateStr = new StringBuilder()
      .append(year).append("-").append(month).append("-").append(day).append(" ")
      .append(hour).append(":").append(minute).append(":").append(second).toString();
System.out.println(dateStr);
   
// StringBuilder is more efficient than String concatenation
String anotherDataStr = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
System.out.println(anotherDataStr);

JDK compiler, in fact, uses both String and StringBuffer to handle string concatenation via the'+' operator. For examples,
String msg = "a" + "b" + "c";

will be compiled into the following codes for better efficiency:

String msg = new StringBuffer().append("a").append("b").append("c").toString();

Two objects are created during the process, an intermediateStringBuffer object and the returnedString object.

Rule of Thumb:Strings are more efficient if they are not modified (because they are shared in the string common pool). However, if you have to modify the content of a string frequently (such as a status message), you should use theStringBuffer class (or theStringBuilder described below) instead.

StringBuilder Class

Java SE 5 introduced a new StringBuilder class (in packagejava.lang), which is almost identical to theStringBuffer class, except that it isnot synchronized. In other words, if multiple threads are accessing aStringBuilder instance at the same time, its integrity cannot be guaranteed. However, for a single-thread program (most commonly), doing away with the overhead of synchronization makes theStringBuilder slightly faster.

StringBuilder is API-compatible with theStringBuffer class, i.e., having the same set of constructors and methods, but with no guarantee of synchronization. It can be a drop-in replacement forStringBuffer under a single-thread environment.

Benchmarking String/StringBuffer/StringBuilder

The following program compare the times taken to reverse a longString via aString object an aStringBuffer.

// Reversing a long String via a String vs. a StringBuffer
public class StringBufferTest {
   public static void main(String[] args) {
      long beginTime, elapsedTime;
   
      // Build a long string
      String str = "";
      int size = 2048;                 // program hangs for size > 4000??
      char c = 'a';
      beginTime = System.nanoTime();   // Reference time in nanoseconds
      for (int count = 0; count < size; count++) {
         str += c;
         c++;
         if (c > 'z') {
            c = 'a';
         }
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Reverse a String by building another String character-by-character in the reverse order
      String strReverse = "";
      beginTime = System.nanoTime();
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         strReverse += str.charAt(pos);   // Concatenate
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Reverse a String via an empty StringBuffer by appending characters in the reverse order
      beginTime = System.nanoTime();
      StringBuffer sb = new StringBuffer(size);
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         sb.append(str.charAt(pos));      // append
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Reverse a String by creating a StringBuffer with the given String and invoke its reverse()
      beginTime = System.nanoTime();
      StringBuffer sb1 = new StringBuffer(str);
      sb1.reverse();     // use reverse() method
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   }
}

Elapsed Time is 17006 us (Building the String)
Elapsed Time is 9370 us  (Reversing via building another String character-by-character)
Elapsed Time is 535 us   (Reversing via an empty StringBuffer and append character-by-character)
Elapsed Time is 148 us   (Reversing via creating a StringBuffer with the given string, then reverse()

Observe that constructing a StringBuffer and then using thereverse() method is 4 times faster than building aStringBuffer character-by-character; and is 60 times faster than using theString object.

// Comparing StringBuffer and StringBuilder via reversing a long string 
public class StringBuilderTest {
   public static void main(String[] args) {
      long beginTime, elapsedTime;
   
      // Build a long string
      String str = "";
      int size = 2048;            // program hangs for size > 4000??
      char c = 'a';
      for (int count = 0; count < size; count++) {
         str += c;
         c++;
         if (c > 'z') {
            c = 'a';
         }
      }
   
      // Reverse a String via an empty StringBuffer by appending characters in the reverse order
      beginTime = System.nanoTime();
      StringBuffer sBuffer1 = new StringBuffer(size);
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         sBuffer1.append(str.charAt(pos));
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Repeat with StringBuilder
      beginTime = System.nanoTime();
      StringBuilder sBuilder1 = new StringBuilder(size);
      for (int pos = str.length() - 1; pos >= 0 ; pos--) {
         sBuilder1.append(str.charAt(pos));
      }
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Reverse a String by creating a StringBuffer with the given String and invoke its reverse()
      beginTime = System.nanoTime();
      StringBuffer sBuffer2 = new StringBuffer(str);
      sBuffer2.reverse();
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   
      // Repeat with StringBuilder
      beginTime = System.nanoTime();
      StringBuffer sBuilder2 = new StringBuffer(str);
      sBuilder2.reverse();
      elapsedTime = System.nanoTime() - beginTime;
      System.out.println("Elapsed Time is " + elapsedTime/1000 + " us");
   }
}

Elapsed Time is 849 us (StringBuffer)
Elapsed Time is 204 us (StringBuilder)
Elapsed Time is 190 us (StringBuffer)
Elapsed Time is 131 us (StringBuilder)

Observer that StringBuilder is always faster than theStringBuilder, although the absolute timing varies from run to run.

java.util.StringTokenizer

Very often, you need to break a line of texts into tokens delimited by white spaces. TheStringTokenizer class supports this.

For example, the following program reverses the words in a String.

// Reverse the words in a String using StringTokenizer
import java.util.StringTokenizer;
public class StringTokenizerTest {
   public static void main(String[] args) {
      String str = "Monday Tuesday Wednesday Thursday Friday Saturday Sunday";
      String strReverse;
      StringBuilder sb = new StringBuilder();
      StringTokenizer st = new StringTokenizer(str);
   
      while (st.hasMoreTokens()) {
         sb.insert(0, st.nextToken());
         if (st.hasMoreTokens()) {
            sb.insert(0, " ");
         }
      }
      strReverse = sb.toString();
      System.out.println(strReverse);
   }
}
// Constructors
StringTokenizer(String s)  // Constructs a StringTokenizer for the given string,
                           // using the default delimiter set of " \t\n\r\f"
                           // (i.e., blank, tab, newline, carriage-return, and form-feed).
                           // Delimiter characters themselves will not be treated as tokens. 
StrintTokenizer(String s, String delimiterSet)  // Use characters in delimiterSet as delimiters.
 
// Methods
boolean hasNextToken()     // Returns true if next token available
String nextToken()         // Returns the next token
 
// Code Sample
StringTokenizer tokenizer = new StringTokenizer(aString);
while (tokenizer.hasNextToken()) {
   String token = tokenizer.nextToken();
   .....
}

The JDK documentation stated that "StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split() method of String or the java.util.regex package instead."

For example, the following program uses the split() method of the String class to reverse the words of a String.


// Reverse the words in a String using split() method of the String class
public class StringSplitTest {
   public static void main(String[] args) {
      String str = "Monday Tuesday Wednesday Thursday Friday Saturday Sunday";
      String[] tokens = str.split("\\s");  // white space '\s' as delimiter
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < tokens.length; i++) {
         sb.insert(0, tokens[i]);
         if (i < tokens.length - 1) {
            sb.insert(0, " ");
         }
      }
      String strReverse = sb.toString();
      System.out.println(strReverse);
   }
}
原文URL:点击打开链接
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
string去除特殊符号有多种方法。其中一种方法是使用trim()函数,可以去除字符串开头和结尾的特殊符号。另外,还可以使用ltrim()函数去除开头的特殊符号,使用rtrim()函数去除末尾的特殊符号。此外,可以使用str_replace()函数来替换特殊符号为空格或其他字符。如果要去除多个特殊符号,可以将这些特殊符号作为数组传递给str_replace()函数。在其他编程语言中,也有类似的方法来去除特殊符号,如Java中的replaceBlank()函数可以去除多个空格、换行符和制表符,以及去除英文逗号和双引号。下面是一些示例代码: 1. 使用trim()函数去除字符串开头和结尾的特殊符号: ```php $str = "#abcdefg#"; $result = trim($str, "#"); ``` 2. 使用ltrim()函数去除字符串开头的特殊符号: ```php $str = "#abcdefg"; $result = ltrim($str, "#"); ``` 3. 使用rtrim()函数去除字符串末尾的特殊符号: ```php $str = "abcdefg#"; $result = rtrim($str, "#"); ``` 4. 使用str_replace()函数替换特殊符号: ```php $str = "#abcdefg#"; $result = str_replace("#", "", $str); ``` Java中的replaceBlank()函数示例: 1. 去除多个空格、换行符和制表符: ```java public String replaceBlank(String str) { String dest = ""; if (str != null) { Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(str); dest = m.replaceAll(""); } return dest; } ``` 2. 去除英文逗号和双引号: ```java public String replaceBlank(String str) { String dest = ""; if (str != null) { dest = str.replace(",", "").replace("\"", ""); } return dest; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值