使用谷歌guava(一):guava基本工具

本文大部分内容翻译自英文书籍《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. 注意事项:

  1. Joiner类连接的对象不局限于字符串,任何对象的数组、集合、可变参数都可以,底层是调用入参各个元素的toString方法得到待连接的字符串。如果没有使用skipNulls或useForNull,遇到null元素将会抛出NPE。

  2. 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. 注意事项

  1. 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类

  1. 追加字符
// 在字符串后面追加字符,返回"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); 
  1. 空字符串处理

看方法名即可知方法功能。

// ""
Strings.nullToEmpty(null);  
// null
Strings.emptyToNull(""); 
// false
Strings.isNullOrEmpty(" "); 
// true
Strings.isNullOrEmpty(""); 
// ZYL
Strings.commonPrefix("ZYL123","ZYL456"); 
// ZZZ
Strings.commonSuffix("123ZZZ","456ZZZ"); 

使用CharMatcher类

字符匹配类,对字符串中的字符进行匹配操作。

CharMatcher对象

  1. 内置的匹配对象
// 匹配任何字符
 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
  1. 自定义匹配对象
// 返回匹配指定字符的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执行匹配及匹配后的处理

  1. 执行匹配

    • 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")
  1. 对匹配的字符进行操作

    • 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();
}
阅读更多
上一篇如何只用4个byte保存用户一个月的签到状态
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭