本文大部分内容翻译自英文书籍《Getting Started with Google Guava》,作者对内容进行了适当补充修改并作了排版优化。
内容概要
- 使用Joiner类将多个字符串以指定分隔符进行连接,涵盖MapJoiner类的使用。
- 使用Splitter类将字符串以指定分隔符进行分割,涵盖MapSplitter类的使用。
- 字符串操作,如去除特定子串,字符串匹配等,主要涉及CharMatcher和Strings类
- 使用Preconditions对变量、参数等进行校验
- 其他基本工具,包括帮助生成对象的toString、hashcode等方法的工具类,以及实现Comparable接口的简易方法
使用Joiner类
1. 将多个字符串以特定分隔符相连
// 不使用guava
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();
}
// 使用guava
String[] stringList=new String[]{"foo","bar",null}
// skipNulls 忽略字符串数组中的null元素,输出“foo|bar”
Joiner.on("|").skipNulls().join(stringList);
// useForNUll 使用指定值替换字符串数组中的null元素,输出"foo|bar|no value"
Joiner.on("|").useForNull("no value").join(stringList);
2. 配合Appendable使用
appendable是个接口,表示可追加的,其常用实现类有stringbuilder及一些IO类如BufferWriter、FileWriter等,使用Joiner可以很方便的向这些对象中追加内容。
例一:
```
StringBuilder sb = new StringBuilder();
Joiner joiner = Joiner.on("|").skipNulls();
//返回StringBuilder实例,打印sb.toString输出"foo|bar|baz"
joiner.appendTo(sb,"foo","bar","baz")
```
例二:
```
FileWriter fileWriter = new FileWriter(new File("path")):
List<Date> dateList = getDates();
Joiner joiner = Joiner.on("#").useForNulls(" ");
//返回FileWriter实例, dateList中的数据以“#”连接后追加至FileWriter实例中
joiner.appendTo(fileWriter,dateList);
```
3. MapJoiner连接Map元素
MapJoiner的功能是将Map中的所有元素以指定分隔符连接在一起形成一个特定格式的字符串,MapJoiner实例的创建方法如下:
/*
* Joiner.on("#")创建了Joiner对象,元素之间以“#”分隔
* 在Joiner对象上调用withKeyValueSeparator("=")创建MapJoiner对象,Map元素的key、value之间以“=”分隔
*/
mapJoiner = Joiner.on("#").withKeyValueSeparator("=");
一个实例:
@Test
public void testMapJoiner() {
String expectedString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
//使用LinkedHashMap保证元素连接的顺序,使用hashMap的话,连接顺序与元素的put顺序可能不一致,这跟hashMap的遍历是一样的
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));
}
3. 注意事项:
Joiner类连接的对象不局限于字符串,任何对象的数组、集合、可变参数都可以,底层是调用入参各个元素的toString方法得到待连接的字符串。如果没有使用skipNulls或useForNull,遇到null元素将会抛出NPE。
Joiner类是不可变的,因此也是线程安全的,可以声明为static final变量以重用。考虑下面的代码:
Joiner stringJoiner = Joiner.on("|").skipNulls();
//useForNull()返回了一个新的Joiner实例,stringJoiner仍引用的是原来的Joiner
stringJoiner.useForNull("missing");
// null元素将被忽略,而不会替换为“missing”,输出"foo|bar"
stringJoiner.join("foo","bar",null);
使用Splitter类
1. 分割字符串
使用String.split:
String testString = "Monday,Tuesday,,Thursday,Friday,,";
//parts的元素为: [Monday, Tuesday, , Thursday,Friday],注意索引2处的空元素
String[] parts = testString.split(",");
使用guava
/*
* on方法参数代表分隔符,可以是字符、字符串、正则表达式
* split方法返回一个包含所有分割后生成的字符串的可迭代对象,打印输出["foo",,,"bar","baz"]
*/
Iterable<String> stringIterable1=Splitter.on('|').split("foo|||bar|baz");
// 以正则表达式作为分隔符,返回["foo","bar","baz"]
Iterable<String> stringIterable2=Splitter.on("\\d+").split("foo123bar45baz")
// 自动去除空元素,返回["foo","bar","baz"]
Splitter.on('|').omitEmptyStrings().split("foo|||bar|baz")
// 自动去除每个元素前后的空字符,返回["foo","bar","baz"]
Splitter.on('|').trimResults().split(" foo|bar | baz ")
// 自动去除每个元素前后的数字,返回["foo","bar","baz"],还可以修剪元素首尾的其他特定字符
Splitter.on('|').trimResults(CharMatcher.DIGIT).split("1foo|bar2|3baz4")
2. 借助MapSplitter
与MapJoiner类似,直接看例子。
String startString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
Splitter.MapSplitter mapSplitter = Splitter.on("#").withKeyValueSeparator("=");
// 返回的是一个不可变的LinkedHasMap,元素顺序与被分割的字符串中的一致
Map<String, String> splitMap = mapSplitter.split(startString);
3. 注意事项
- Splitter与Joiner一样也是不可变且线程安全的。
Splitter splitter = Splitter.on('|');
//下面的代码将返回一个新的实例,不会影响上面的splitter
splitter.trimResults();
//输出结果仍然包括空元素[1,2,3,,,]
Iterable<String> parts = splitter.split("1|2|3|||");
使用Charsets类
该类非常简单,只是简单封装了java支持的六种标准字符集。
不使用Charsets:
try{
bytes = "foobarbaz".getBytes("UTF-8");
}catch (UnsupportedEncodingException e){
//程序不可能走到这,“UTF-8”必须支持
}
使用Charsets:
// 杜绝了拼写错误的可能,且不会抛出UnsupportedEncodingException
byte[] bytes2 = "foobarbaz".getBytes(Charsets.UTF_8);
使用Strings类
- 追加字符
// 在字符串后面追加字符,返回"fooxxx";第二个参数6代表返回字符串的最小长度,而非追加的次数,如输入字符串长度已超出6,则不会进行追加操作,也不会裁剪,而是原样返回
Strings.padEnd("foo",6,'x');
// 已超过6位,原样返回“foo4567”
Strings.padEnd("foo4567",6,'x');
// 在字符串前面追加字符,返回"xxxfoo",用法同padEnd
Strings.padStart("foo",6,'x');
// 重复给定字符串,返回"ZYLZYLZYL"
Strings.repeat("ZYL", 3);
- 空字符串处理
看方法名即可知方法功能。
// ""
Strings.nullToEmpty(null);
// null
Strings.emptyToNull("");
// false
Strings.isNullOrEmpty(" ");
// true
Strings.isNullOrEmpty("");
// ZYL
Strings.commonPrefix("ZYL123","ZYL456");
// ZZZ
Strings.commonSuffix("123ZZZ","456ZZZ");
使用CharMatcher类
字符匹配类,对字符串中的字符进行匹配操作。
CharMatcher对象
- 内置的匹配对象
// 匹配任何字符
ANY
// 匹配ASCII字符
ASCII
// 匹配所有可换行的空白字符(不包括非换行空白字符,例如"\u00a0")
BREAKING_WHITESPACE
// 匹配ASCII数字
DIGIT
// 匹配所有看不见的字符
INVISIBLE
// 匹配UNICODE数字, 使用 Character.isDigit() 实现
JAVA_DIGIT
// 匹配ISO控制字符, 使用 Charater.isISOControl() 实现
JAVA_ISO_CONTROL
// 匹配字母, 使用 Charater.isLetter() 实现
JAVA_LETTER
// 匹配数字或字母
JAVA_LETTER_OR_DIGET
// 匹配小写
JAVA_LOWER_CASE
// 匹配大写
JAVA_UPPER_CASE
// 不匹配所有字符
NONE
// 匹配单字宽字符, 如中文字就是双字宽
SINGLE_WIDTH
// 匹配所有空白字符
WHITESPACE
- 自定义匹配对象
// 返回匹配指定字符的Matcher
CharMatcher is(char match)
// 返回不匹配指定字符的Matcher
CharMatcher isNot(char match)
// 返回匹配sequence中任意字符的Matcher
CharMatcher anyOf(CharSequence sequence)
// 返回不匹配sequence中任何一个字符的Matcher
CharMatcher noneOf(CharSequence sequence)
// 返回匹配范围内任意字符的Matcher
CharMatcher inRange(char startInclusive, char endIncludesive)
// 返回使用predicate的apply()判断匹配的Matcher
CharMatcher forPredicate(Predicate<? super Charater> predicate)
// 返回以当前Matcher判断规则相反的Matcher
CharMatcher negate()
// 返回与other匹配条件组合做与来判断的Matcher
CharMatcher and(CharMatcher other)
// 返回与other匹配条件组合做或来判断的Matcher
CharMatcher or(CharMatcher other)
CharMatcher执行匹配及匹配后的处理
执行匹配
- boolean matchesAnyOf(CharSequence sequence) 只要sequence中有任意字符能匹配Matcher,返回true
// true
CharMatcher.JAVA_LETTER.matchesAnyOf("123a456")
// false
CharMatcher.JAVA_LETTER.matchesAnyOf("123456")
- boolean matchesAllOf(CharSequence sequence) sequence中所有字符都能匹配Matcher才返回true
// false
CharMatcher.DIGIT.matchesAllOf("123a456")
// true
CharMatcher.DIGIT.matchesAllOf("123456")
- boolean matchesNoneOf(CharSequence sequence) sequence中所有字符都不能匹配Matcher,返回true
// false
CharMatcher.JAVA_LOWER_CASE.matchesNoneOf("ABc")
// true
CharMatcher.JAVA_LOWER_CASE.matchesNoneOf("ABC")
- int indexIn(CharSequence sequence) 返回sequence中匹配到的第一个字符的坐标
// 0
CharMatcher.JAVA_UPPER_CASE.indexIn("AbcDef")
- int indexIn(CharSequence sequence, int start) 返回从start开始,在sequence中匹配到的第一个字符的坐标
// 3
CharMatcher.JAVA_UPPER_CASE.indexIn("AbcDef", 1)
- int lastIndexIn(CharSequence sequence) 返回sequence中最后一次匹配到的字符的坐标
// 7
CharMatcher.anyOf("abc").lastIndexIn("123a456b")
- int countIn(CharSequence sequence) 返回sequence中匹配到的字符计数
// 8
CharMatcher.JAVA_LETTER_OR_DIGIT.countIn("123a456b")
对匹配的字符进行操作
- String removeFrom(CharSequence sequence) 删除sequence中匹配到到的字符并返回
// 123456
CharMatcher.inRange('a','z').removeFrom("abc123def456")
- String retainFrom(CharSequence sequence) 保留sequence中匹配到的字符并返回
// abcdef
CharMatcher.inRange('a','z').retainFrom("abc123def456")
- String replaceFrom(CharSequence sequence, char replacement) 替换sequence中匹配到的字符并返回
// ***123***456
CharMatcher.inRange('a','z').replaceFrom("abc123def456","*")
- String trimFrom(CharSequence sequence) 删除首尾匹配到的字符并返回
// 123def456
CharMatcher.inRange('a','z').trimFrom("abc123def456ghi");
- String trimLeadingFrom(CharSequence sequence) 删除首部匹配到的字符
// 123def456ghi
CharMatcher.inRange('a','z').trimLeadingFrom("abc123def456ghi");
- String trimTrailingFrom(CharSequence sequence) 删除尾部匹配到的字符
// abc123def456
CharMatcher.inRange('a','z').trimTrailingFrom("abc123def456ghi");
- String collapseFrom(CharSequence sequence, char replacement) 将连续匹配的字符替换成replacement
// *123*456*
CharMatcher.inRange('a','z').collapseFrom("abc123def456ghi",'*');
- String trimAndCollapseFrom(CharSequence sequence, char replacement) 先trim再replace
// 123*456
CharMatcher.inRange('a','z').trimAndCollapseFrom("abc123def456",'*')
使用Precondition类
本类的主要功能是对参数进行校验。
// 检查参数是否为null,如不是null,原样返回,否则抛NPE,message为异常说明信息,下同
checkNotNull (T object,Object message)
// 检查索引是否越界,参数size为数组或集合的大小,如不越界原样返回,否则抛IndexOutOfBoundsException
checkElementIndex (int index , int size , Object message)
// 检查参数是否满足表达式,无返回值,表达式expression为false将抛IllegalArgumentException
checkArgument (Boolean expression, Object message)
// 检查参数是否满足表达式,无返回值,表达式expression为false将抛IllegalStateException
checkState (Boolean expression, Object message)
对象工具
- 协助实现对象的toString方法
// 一个含title、author等字段的POJO的toString方法
public String toString() {
return Objects.toStringHelper(this)
// 忽略null值字段
.omitNullValues()
// 设置需要输出的字段
.add("title", title)
.add("author", author)
.add("publisher", publisher)
.add("price",price)
.add("isbn", isbn).toString();
}
- 协助实现对象的hashcode方法
public int hashCode() {
// 参数均为对象的属性
return Objects.hashCode(title, author, publisher, isbn);
}
- 协助实现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();
}