Snapshot API Docs for Guava: https://guava.dev/releases/snapshot-jre/api/docs/
使用Joiner类
public String buildString(List<String> stringList, String delimiter) {
StringBuilder builder = new StringBuilder();
for (String s : stringList) {
if (s != null) {
builder.append(s).append(delimiter);
}
}
builder.setLength(builder.length() - delimiter.length());
return builder.toString();
}
完成上述功能,假设分隔符为"|",使用Joiner类:
Joiner.on("|").skipNulls().join(stringList);// return String
如果想用一个替代品代替null值,可以这样:
Joiner.on("|").useForNull("no value").join(stringList);
注意,Joiner类不是严格地只工作于strings,你可以传参为array、iterable、varargs of any Object。
返回结果是通过为每个传参元素调用Object.toString()完成的。但后果是如果没有使用skipNulls或useForNull,则会抛出NullPointerException异常。
一旦创建,一个Joiner类对象是不可变的(immutable),因此它是线程安全的(thread-safe),它可以使用static final修饰。记住这段话,然后看下面例子:
1. Joiner stringJoiner = Joiner.on("|").skipNulls();
2. stringJoiner.useForNull("missing");
3. stringJoiner.join("foo", "bar", null);
第1行,创建一个Joiner实例。第2行,是创建了一个【新的】Joiner实例。所以,第2行的useForNull()对原来的Joiner实例不起效果。第3行返回的结果是skipNulls()的效果。相当于是如下:(所以记住:Joiner类对象是不可变的(immutable))
1. Joiner stringJoiner = Joiner.on("|").skipNulls();
2. Joiner newStrJoiner = stringJoiner.useForNull("missing");
3. String newStr = stringJoiner.join("foo", "bar", null);
Joiner类也有方法appendTo()作用于StringBuiler:
StringBuilder stringBuilder = new StringBuilder();
Joiner joiner = Joiner.on("|").skipNulls();
joiner.appendTo(stringBuilder, "foo", "bar", "baz");// return StringBuilder instance
Joiner类还可用于实现了Appendable接口的对象:
Class FileWriter
java.lang.Object
java.io.Writer
java.io.OutputStreamWriter
java.io.FileWriter
All Implemented Interfaces:
Closeable, Flushable, 【Appendable】, AutoCloseable
FileWriter fileWriter = new FileWriter(new File("path"));
List<Date> dateList = getDates();
Joiner joiner = Joiner.on("#").useForNulls(" ");
joiner.appendTo(fileWriter, dateList);// return FileWriter instance
Joiner类append the joined list of dates to the FileWriter instance and then return the FileWriter instance。
MapJoiner类
MapJoiner mapJoiner = Joiner.on("#").withKeyValueSeparator("=");
Joiner.on("#")创建一个Joiner对象,然后调用withKeyValueSeparator方法,这时Joiner实例就构建一个MapJoiner对象。
下面是一个单元测试,证实MapJoiner方法的使用:
import java.util.Map;
import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import org.junit.Test;
import static org.junit.Assert.*;// 静态导入
import static org.hamcrest.CoreMatchers.*;// 静态导入
public class App {
@Test
public void testMapJoiner() {
String expectedString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
// 使用LinkedHashMap,原始插入的顺序被保留
Map<String, String> testMap = Maps.newLinkedHashMap();
testMap.put("Washington D.C", "Redskins");
testMap.put("New York City", "Giants");
testMap.put("Philadelphia", "Eagles");
testMap.put("Dallas", "Cowboys");
String returnedString = Joiner.on("#").withKeyValueSeparator("=").join(testMap);
assertThat(returnedString, is(expectedString));
}
}
对于JUnit,assertThat()<=>org.junit.Assert.assertThat(),is()<=>org.hamcrest.CoreMatchers.is()。
使用Splitter类
String testString = "Monday,Tuesday,,Thursday,Friday,,";
String[] parts = testString.split(",");
一个Splitter类可以操作单个字符、字符串、java.util.regex.Pattern、正则表达式、CharMather类。
Splitter.on('|').split("foo|bar|baz");
Splitter splitter = Splitter.on("\\d+");
Splitter splitter = Splitter.on('|').trimResults();// 删除任何开头或结尾的空格
就像Joiner类,Splitter在创建时是不可变的(immutable),所以要注意不要在创建了一个原始的Splitter类后,单独调用trimResults。
Splitter splitter = Splitter.on('|');
splitter.trimResults();// 创建一个新实例,不改变原始对象
Iterable<String> parts = splitter.split("1|2|3|||");// 结果仍然包含空元素
MapSplitter类
MapSplitter是Splitter的一个内部类。
Splitter.MapSplitter mapSplitter = Splitter.on("#").withKeyValueSeparator("=");
@Test
public void testSplitter() {
String startString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
Map<String, String> testMap = Maps.newLinkedHashMap();
testMap.put("Washington D.C", "Redskins");
testMap.put("New York City", "Giants");
testMap.put("Philadelphia", "Eagles");
testMap.put("Dallas", "Cowboys");
Splitter.MapSplitter mapSplitter = Splitter.on("#").withKeyValueSeparator("=");
Map<String, String> splitMap = mapSplitter.split(startString);
assertThat(testMap, is(splitMap));
}
在Guava中操作strings
使用Charsets类
byte[] bytes = someString.getBytes();
try {
bytes = "foobarbaz".getBytes("UTF-8");
} catch(UnsupportedEncodingException e) {
// TODO
}
如果系统的默认字符集不是你预期要去处理的,就会抛出异常。
注:UTF-8是Java平台必须支持的,所以上面UnsupportedEncodingException永远不会抛出。
Charsets类提供对6种字符集的static final引用。这样就不会出现拼写错误导致问题。
byte[] bytes = "foobarbaz".getBytes(Charsets.UTF_8);
使用Strings类
StringBuilder builder = new StringBuilder("foo");
char c = 'x';
for (int i=0; i<3;i++) {
builder.append(c);
}
return builder.toString();
以上6行代码可以用下面1行代码替代:
Strings.padEnd("foo", 6, 'x');
第2个参数是返回的字符串的最小长度。
String.padStart("foo", 6, 'x');
=> xxxfoo
处理可能的null值:
nullToEmpty:如果string长度==0或string==null,返回"";否则返回原string。
emptyToNull:如果string长度==0或string==null,返回null;否则返回原string。
isNullOrEmpty:如果string长度==0或string==null,返回true;否则返回false。
使用CharMatcher类
下面代码将多行字符串用一个空格代替换行符,格式化为一条。
CharMatcher.BREAKING_WHITESPACE.replaceFrom(stringWithLinebreaks, ' ');
其中,stringWithLinebreaks可以是字符串也可以是CharSequence对象。
@Test
public void testRemoveWithWhiteSpace() {
String tabsAndSpaces = " String with spaces and tabs";
String expected = "String with spaces and tabs";
String scrubbed = CharMatcher.WHITESPACE.collapseFrom(tabsAndSpaces, ' ');
assert(scrubbed, is(excepted);
}
要删除任何开头或结尾的空格,用trimAndCollapseFrom方法就可以了。
如果我们要保持匹配的字符呢?
@Test
public void testRetainFrom() {
String lettersAndNumbers = "foo989yxbar234";
String expected = "989234";
String retained = CharMatcher.JAVA_DIGIT.retainFrom(lettersAndNumbers);
assertThat(expected, is(retained));
}
你还可以为numbers或whitespace创建一个matcher:
CharMatcher cm = CharMatcher.JAVA_DIGIT.or(CharMatcher.WHITESPACE);
使用Preconditions类
if (someObj == null) {
throw new IllegalArgumentException("someObj must not be null");
}
通过使用Preconditions(使用静态导入),我们检查null参数更加精确:
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) {
this.label = checkNotNull(label, "Label can't be null");
}
public void updateCurrentIndexValue(int index, int valueToSet) {
this.currentIndex = checkElementIndex(index, values.length, "Index out of bounds for values");
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;
}
}
checkNotNull(T object, Object message):如果object不为null,则返回object,否则抛出NullPointerException。
checkElementIndex(int index, int size, Object message):size参数是array、list或string的长度。如果有效则返回index,否则抛出IndexOutOfBoundsException。
checkArgument(Boolean expression, Object message):Boolean表达式期望为true,否则抛出IllegalArgumentException。
checkState(Boolean expression, Object message):Boolean表达式期望为true,否则抛出IllegalArgumentException。
Object工具
生成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();
}
}
检查null值
String value = Objects.firstNonNull(someString, "default value");
如果不确定someString是否为null值,可以提供一个默认值。如果两个参数都为null,则抛出NullPointerException。
产生hash codes
public int hashCode() {
return Objects.hashCode(title, author, publisher, isbn);
}
实现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();
}
ComparisonChain类在遇到第一个非0结果后就会停止作比较。只有所有比较都为0结果才为0。