文章目錄
Joiner
Joiner可以通過一個給定的分隔符將多個字符串連接起來。
Joiner.on("|").skipNulls().join(stringList);
Joiner.on("|").useForNull("no value").join(stringList);
關於使用Joiner類,需要強調幾點:Joiner類不僅限於使用strings。 還可以傳入an array, iterable, or varargs of any object。 最終的結果是通過調用傳入的每個元素的Object.toString()。因此,如果未使用skipNulls或useForNull方法,在遇到空對象元素時將拋出NullPointerException錯誤。另外,一旦創建,Joiner對象是不可變的,因此是線程安全的,並且可以用作static final 變量。 考慮到這一點,請考慮以下代碼段:
Joiner stringJoiner = Joiner.on("|").skipNulls();
//userForNull方法返回一個新的Joiner實例。stringJoiner實例保持不變
stringJoiner.useForNull("missing");
stringJoiner.join("foo","bar",null);
在上面的代碼中,useForNull()
方法的調用對原來的Joiner實例沒有影響。調用stringJoiner.join()
方法的調用依然會忽略null值。
Joiner類不但可以返回strings,還有可以與StringBuilder類配合使用的方法:
StringBuilder stringBuilder = new StringBuilder();
Joiner joiner = Joiner.on("|").skipNulls();
//returns the StringBuilder instance with the values foo,bar,baz appeneded with "|" delimiters
joiner.appendTo(stringBuilder,"foo","bar","baz")
在上面給出的例子中,我們給Joiner類的入參爲一個StringBuilder實例,返回參數也是一個StringBuilder對象。
Joiner類可以和實現了Appendable接口的類一起使用:
FileWriter fileWriter = new FileWriter(new File("path")):
List<Date> dateList = getDates();
Joiner joiner = Joiner.on("#").useForNulls(" ");
//returns the FileWriter instance with the values appended into it
joiner.appendTo(fileWriter,dateList);
在這裏給出的例子中,appendTo的返回參數爲FilteWriter實例。
MapJoiner
MapJoiner方法的工作方式與Joiner類類似,但它將給定的字符串作爲具有指定分隔符的鍵值對連接。 MapJoiner方法創建如下:
mapJoiner = Joiner.on("#").withKeyValueSeparator("=");
這行代碼可分爲兩步:
- Joiner.on("#")方法創建了一個Joiner對象。
- 通過Joiner實例的withKeyValueSeparator方法會構造一個MapJoiner對象。
Splitter
給定一個字符串和一個分隔符,Splitter可以利用給定的分隔符將字符串分割成多個子字符串。
相對於String.split方法的好處
String testString = "Monday,Tuesday,,Thursday,Friday,,";
//parts is [Monday, Tuesday, , Thursday,Friday]
String[] parts = testString.split(",");
從上面的例子中可以看到String.split方法將最後的兩個實體丟棄了。這種結果在某些情況下是你想要的,但有些情況下卻不是。因此這類操作應該留給編程人員決定。
Splitter.on("|").split("foo|bar|baz");
//以1個或多個連續的數字爲分割符
Splitter splitter = Splitter.on("\\d+");
//Splits on '|' and removes any leading or trailing whitespace(與上面String.split方法操作結果相同)
Splitter splitter = Splitter.on('|').trimResults();
與Joiner的不可變性類似,Splitter實例在創建後也是不可變對象
Splitter splitter = Splitter.on('|');
//Next call returns a new instance, does not modify the original!
splitter.trimResults();
//Result would still contain empty elements
Iterable<String> parts = splitter.split("1|2|3|||");
MapSplitter
//MapSplitter is defined as an inner class of Splitter
Splitter.MapSplitter mapSplitter = Splitter.on("#").withKeyValueSeparator("=");
Strings
Charsets
反例:
try{
byte[] bytes = "foobarbaz".getBytes("UTF-8");
}catch (UnsupportedEncodingException e){
//This really can't happen UTF-8 must be supported
}
分析這段代碼我們可以得知:由於Java平臺必須支持UTF-8字符集,所以實際上這段代碼永遠不會拋出UnsupportedEncodingException錯誤。但由於我們這裏使用字符串來指定字符集定義,因此我們可能會出現拼寫錯誤,這會導致異常被拋出。而使用CharSets類可以更好的完成這項工作。值得注意的是:自從Java7開始,JDK中提供了StandardCharsets類來完成相同的功能。
byte[] bytes2 = "foobarbaz".getBytes(Charsets.UTF_8);
Strings
Strings類提供了許多方便的工具方法來操縱字符串。首先看一下使用這個類的一個例子:
StringBuilder builder = new StringBuilder("foo");
char c = 'x';
for(int i=0; i<3; i++){
builder.append(c);
}
return builder.toString();
以上是沒有guava時,在一個字符串後面追加3個x字符的實現。使用guava後,只需一行代碼就可以完成。
Strings.padEnd("foo",6,'x');
這裏需要注意的是第二個參數-6,它指定了調用方法返回的字符串長度的最小值而不是在原始的字符串上追加多少次x字符。如果提供的字符串長度已經等於或大於6,那麼不會追加任何字符。Strings類還有一個對應的padStart
方法,這個方法在給定字符串的前面插入字符。
除此以外,Strings類中有三個非常有用的方法,專門用於處理可能的null值:
- nullToEmpty
- emptyToNull
- isNullOrEmpty
It would probably be a good idea to always use the nullToEmpty method on any string objects passed as argument.
CharMatcher
下面的例子將多行的字符串變成一行,以空格分隔開每一行。
CharMatcher.BREAKING_WHITESPACE.replaceFrom(stringWithLinebreaks,' ');
下面給出的代碼是移除多個連續的tab和space,並替換成一個space。
@Test
public void testRemoveWhiteSpace(){
String tabsAndSpaces = "String with spaces and tabs";
String expected = "String with spaces and tabs";
String scrubbed = CharMatcher.WHITESPACE.
collapseFrom(tabsAndSpaces,' ');
assertThat(scrubbed,is(expected));
}
//將字符串前端的連續空格也刪除調
@Test
public void testTrimRemoveWhiteSpace(){
String tabsAndSpaces = " String with spaces and tabs";
String expected = "String with spaces and tabs";
String scrubbed = CharMatcher.WHITESPACE.trimAndCollapseFrom(tabsAndSpaces,' ');
assertThat(scrubbed,is(expected));
}
除了替換一組匹配的字符集合外,CharMatcher還可以提取出匹配的字符集合。看下面的例子:
@Test
public void testRetainFrom(){
String lettersAndNumbers = "foo989yxbar234";
String expected = "989234";
String retained = CharMatcher.JAVA_DIGIT.retainFrom(lettersAndNumbers);
assertThat(expected,is(retained));
}
最後,CharMatcher還有一個強大的功能:通過組合CharMatcher類來構建一個新的CharMatcher。下面讓我們來看看如何構造出一個匹配數字(numbers)或者whitespace的matcher。
CharMatcher cm = CharMatcher.JAVA_DIGIT.or(CharMatcher.WHITESPACE);
Preconditions
Preconditions類是用於驗證我們代碼狀態的靜態方法集合。 Preconditions非常重要,因爲他們確保代碼的成功執行符合我們的預期。 如果條件與我們的預期不同,我們會立即獲得有關問題所在位置的反饋。 和以前一樣,使用前置條件對於確保代碼的行爲很重要,並且在調試時非常有用。
反例:我們常常會寫出下面的代碼
if(someObj == null){
throw new IllegalArgumentException(" someObj must not be null");
}
如果使用Preconditions類。對於檢查null參數,我們可以寫出如下更簡潔的代碼。
Preconditions.checkNotNull(someObj,"someObj must not be null");
下面是更復雜的一個例子:
public class PreconditionExample {
private String label;
private int[] values = new int[5];
private int currentIndex;
public PreconditionExample(String label) {
//returns value of object if not null
this.label = checkNotNull(label,"Label can''t be null");
}
public void updateCurrentIndexValue(int index, int valueToSet) {
//Check index valid first
this.currentIndex = checkElementIndex(index, values.length, "Index out of bounds for values");
//Validate valueToSet
checkArgument(valueToSet <= 100,"Value can't be more than 100");
values[this.currentIndex] = valueToSet;
}
public void doOperation(){
checkState(validateObjectState(),"Can't perform operation");
}
private boolean validateObjectState(){
return this.label.equalsIgnoreCase("open") && values[this.currentIndex]==10;
}
}
Objects
Getting help with the toString method
在debugging時,toString方法非常必要。然而自己來寫一個toString方法非常單調無味。而Objects類通過toStringHelper方法可以使得這個工作非常簡單。下面是給出的例子:
public class Book implements Comparable<Book> {
private Person author;
private String title;
private String publisher;
private String isbn;
private double price;
....
public String toString() {
return Objects.toStringHelper(this)
.omitNullValues()
.add("title", title)
.add("author", author)
.add("publisher", publisher)
.add("price",price)
.add("isbn", isbn).toString();
}
這個toString方法共完成了3項工作:
- 首先我們將Book對象的引用傳入toStringHelper方法,生成了一個Objects.ToStringHelper實例。(最新版本的guava已經將這個方法標記爲deprecated。使用MoreObjects.toStringHelper方法替代)
- omitNullValues方法的調用會排除添加任何null屬性值。
- 每次調用add都會提供一個標籤和屬性,以包含在Book對象的字符串表示中。
Checking for null values
String value = Objects.firstNonNull(someString,""default value"");
firstNonNull方法傳入兩個參數,返回第一個不是null的參數。該方法常用於給一個不確定是否爲null的對象提供一個默認值。需要謹慎一些的是:如果兩個參數都爲null,方法會拋出NullPointerException。
Generating hash codes
Objects利用hashCode方法可以很方便的實現一個對象的hashCode方法。
public int hashCode() {
return Objects.hashCode(title, author, publisher, isbn);
}
ComparisonChain:Implementing CompareTo
以下是compareTo方法的典型實現:
public int compareTo(Book o) {
int result = this.title.compareTo(o.getTitle());
if (result != 0) {
return result;
}
result = this.author.compareTo(o.getAuthor());
if (result != 0) {
return result;
}
result = this.publisher.compareTo(o.getPublisher());
if(result !=0 ) {
return result;
}
return this.isbn.compareTo(o.getIsbn());
}
下面對比一下使用ComparisonChain類的compareTo實現
public int compareTo(Book o) {
return ComparisonChain.start()
.compare(this.title, o.getTitle())
.compare(this.author, o.getAuthor())
.compare(this.publisher, o.getPublisher())
.compare(this.isbn, o.getIsbn())
.compare(this.price, o.getPrice())
.result();
}
第二種寫法不但更緊湊而且更容易閱讀。