Joiner

将一个字符串序列用一个分隔符连接起来还是比较棘手的 — 但不应该是这样。如果序列包含null就更困难了,流式风格的Joiner让这一切变得简单起来。

  1. Joiner joiner = Joiner.on("; ").skipNulls();
  2. return joiner.join("Harry", null, "Ron", "Hermione");

以上代码返回的是”Harry; Ron; Hermione”。另外,也可以使用useForNull(String)来指定一个字符串作为null的替代。

同样,Joiner也可以在Object上,使用toString()转换成字符串然后再合并。

  1. //返回1,5,7
  2. Joiner.on(",").join(Arrays.asList(1,5,7));

注意:Joiner实例总是不可变的。Joiner的配置方法总是返回一个新的Joiner实例。这让Joiner是线程安全的,并且可用于静态常量。

Splitter

Java内置的分割字符串的工具的行为有点奇怪。例如String.split会默认的丢弃路径分隔符,而StringTokenizer会将其表示为5个空格。

小测试:”,a,,b,”.split(“,”)的结果是什么?

  1. “”, “a”, “”, “b”, “”
  2. null, “a”, null, “b”, null
  3. “a”, null, “b”
  4. “a”, “b”
  5. 以上都不是

正确的答案是5:””, “a”, “”, “b”,只有最后一个空字符串被忽略,为什么会这样我也不太清楚。

Splitter允许你安心的直接使用流式模式来完全控制这些令人困惑的行为。

  1. Splitter.on(",")
  2. .trimResults()
  3. .omitEmptyStrings()
  4. .split("foo,bar,, qux");

以上的代码返回的是一个Iterable<String>,其中包含”foo”,”bar”,”qux”。Splitter可用于任何Pattern, char, StringCharMatcher

基本工厂方法

方法 描述 示例
Splitter.on(char) 使用单独的一个字符分隔指定序列 Splitter.on(‘;’)
Splitter.on(CharMatcher) 使用某类的字符分隔指定序列 Splitter.on(CharMatcher.BREAKING_WHITE) Splitter.on(CharMatcher.anyOf(“;,.”))
Splitter.on(String) 使用字符串分隔指定序列 Splitter.on(“, “)
Splitter.on(Pattern) Splitter.onPattern(String) 根据正则表达式分隔指定序列 Splitter.onPattern(“\r?\n”)
Splitter.fixedLength(int) 将指定序列分隔成指定长度的子串,最后一个子串可能小于指定的值,但永远不可能为空 Splitter.fixedLength(3)

配置
方法 | 描述 | 示例
—- | —- | —-
omitEmptyStrings() | 在结果中忽略空字符串 | Splitter.on(‘,’).omitEmptyStrings().split(“a,,c,d”)会返回”a”,”c”,”d”
trimResults() | 剔除结果中的空格,相当于trimResults(CharMatcher.WHITESPACE) | Splitter.on(‘,’).trimResults().split(“a, b, c, d”)会返回”a”, “b”, “c”, “d”
trimResults(CharMatcher) | 剔除结果中的指定字符 | Splitter.on(‘,’).trimResults(CharMatcher.is(‘‘)).split(“_a ,_b ,c_”)会返回”a “, “b “, “c”
limit(int) | 字符串分割的最大数量(即将分隔成几部分,最后一部分包含所有剩下的字符串,不会再进行分隔) | Splitter.on(‘,’).limit(3).split(“a,b,c,d”)会返回”a”, “b”, “c,d”

TODO:Map分割

如果希望返回List,使用Lists.newArrayList(Splitter.split(String))或类似方法即可。

注意:Splitter实例是不可变的。分割器的配置方法始终返回一个新的Splitter。这样会使Splitter是线程安全的,并且可以用作常量。

CharMatcher

之前,我们的StringUtil类变成了未经检查的,它有许多以下类似的方法:

- - - - -
allAscii collapse collapseControlChars collapseWhitespace indexOfChars
lastIndexNotOf numSharedChars removeChars removeCrLf replaceChars
retainAllChars strip stripAndCollapse stripNonDigits

这些方法表示了一个跨产品的两个概念:

  1. 一个“匹配”的字符由什么组成?
  2. 对这些“匹配”的字符要做什么?

为了简化这个困境,我们开发了CharMatcher这个类。

可以把CharMatcher直观的想象成是一个表示字符的特殊类,像数字或空格之类。实际上,CharMatcher就是一个字符的布尔判判断 — 它实现了Predicate<Character>接口,因为它太常用了,例如:所有空格,所有小写字母等,Guava才为字符提供了这个API。

CharMatcher的作用就是在一个字符序列上执行一系列的操作:裁剪,折叠,移除,保留等等。一个CharMatcher类型的对象表示:

  1. 一个“匹配”的字符由什么组成?
    有很多操作来回答这个问题。
  2. 对这些“匹配”的字符要做什么?
    The result is that API complexity increases linearly for quadratically increasing flexibility and power. Yay!
  1. String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(string);
  2. //删除控制字符
  3. String theDigits = CharMatcher.DIGIT.retainFrom(string);
  4. //仅保留数字
  5. String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' ');
  6. //剔除结尾的空白,并将空白替换为单个的空格
  7. String noDigits = CharMatcher.JAVA_DIGIT.replaceFrom(string, "*");
  8. String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(string);
  9. //删除所有不是数字和小写字母的字符

_注意:CharMatcher仅接受char值,不接受从0x10000到0x10FFFF之间的Unicode代码值。这些逻辑字符是使用surrogate pair编码为String的,CharMatcher将其作为两个分开的字符处理。

获取CharMatcher

很多需求都可以使用已提供的CharMatcher常量:

- - - - -
ANY NONE WHITESPACE BREAKING_WHITESPACE INVISIABLE
DIGIT JAVA_LETTER JAVA_DIGIT JAVA_LETTER_OR_DIGIT JAVA_ISO_CONTROL
JAVA_LOWER_CASE JAVA_UPPER_CASE ASCII SINGLE_WIDTH

其他获取CharMatcher的常规方法包括:

方法 描述
anyOf(CharSequence) 包括想要匹配的所有字符。例如CharMatcher.anyOf("aeiou")匹配所有小写的元音字符
is(char) 匹配指定的字符
inRange(char, char) 匹配一个范围内的字符,例如CharMatcher.inRange('a', 'z')

另外,还有negate()and(CharMatcher)or(CharMatcher),这些方法提供CharMatcher的简单布尔操作。

使用CharMatcher

CharMatcher提供了很多操作CharSequence的方法。以下列出的是常用的方法,更多方法参加Javadoc文档:

方法 描述
collapseFrom(CharSequence, char) 讲连续匹配的字符替换为指定的字符,例如:WHITESPACE.collapseFrom(string, ' ')会将连续的空白符替换为一个单一的空格。
matchesAllOf(CharSequence) 测试是否匹配所有字符。例如ASCII.matchesAllOf(string)检查string中的字符是否都是ASCII。
removeFrom(CharSequence) 从字符序列中删除匹配的字符
retainFrom(CharSequence) 从字符序列中删除不匹配的字符(仅保留匹配的字符)
trimFrom(CharSequence) 从字符序列的头尾删除指定的字符
replaceFrom(CharSequence, CharSequence) 用指定字符序列替换匹配的字符

(注意:这些方法都返回一个StringmatchesAllOf返回boolean

Charsets

不要像下面这样做:

  1. try {
  2. bytes = string.getBytes("UTF-8");
  3. } catch (UnSupportedEncodingException e) {
  4. throw new AssertError(e);
  5. }

而要这么做:

  1. bytes = string.getBytes(Charsets.UTF_8);

Charsets提供了6种Charset的标准实现的常量引用,保证被所有Java平台实现支持。使用它们的名字来引用。

TODO:Charsets说明和应用场景

(注意:如果你使用JDK7,应该使用StandardCharsets中的常量!)

CaseFormat

CaseFormat是一个用来转换ASCII大小写的工具类 — 例如,编程语言的命名约定。支持的格式如下:

格式 示例
LOWER_CAMEL lowerCamel
LOWER_HYPHEN lower-hyphen
LOWER_UNDERSCORE lower_underscore
UPPER_CAMEL UpperCamel
UPPER_UNDERSCORE UPPER_UNDERSCORE
  1. CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME");
  2. //返回"constantName"