Joiner
将一些普通的字符串以固定的分隔符组装在一起是我们在平常工作遇到的,比如将一个Array,List,iterable包含的内容组转成字符串,最常见的就是使用循环将字符串拼接在StringBuilder上,一般的代码如下:
@Test
public void listJoiner() {
String[] str = {"1", "3", "3", "3", "3", "3"};
String result = "";
for (int i = 0; i < str.length; i++) {
if (i != str.length-1)
str[i] = str[i] + ",";
result = result+str[i];
}
System.err.println(result);
}
这段代码要注意的就是要将最后一个分隔符去掉。这段代码不是很复杂,但是没有什么价值,完全可以使用Joiner类实现。 下面是一个简单的例子,使用Joiner类以 “|” 将字符串分隔:
Joiner.on(",").skipNulls().join(str);
被拼接的对象集,可以是硬编码的少数几个对象,可以是实现了 Iterable 接口的集合,也可以是迭代器对象。
除了返回一个拼接过的字符串,Joiner 还可以在实现了 Appendable 接口的对象所维护的内容的末尾,追加字符串拼接的结果。
StringBuilder sb = new StringBuilder("result:");
Joiner.on(" ").appendTo(sb, 1, 2, 3);
System.out.println(sb);//result:1 2 3
Guava 对空指针有着严格的限制,如果传入的对象中包含空指针,Joiner 会直接抛出 NPE。与此同时,Joiner 提供了两个方法,让我们能够优雅的处理待拼接集合中的空指针。
如果我们希望忽略空指针,那么可以调用 skipNulls 方法,得到一个会跳过空指针的 Joiner 实例。如果希望将空指针变为某个指定的值,那么可以调用 useForNull 方法,指定用来替换空指针的字符串。
Joiner.on(' ').skipNulls().join(1, null, 3);//1 3
Joiner.on(' ').useForNull("None").join(1, null, 3);//1 None 3
package strings;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
/**
* Created by LF on 2017/3/6.
*/
public class Myjoiner {
private static final List<String> list = Lists.newArrayList("a", "b", "c", "d");
private static final List<String> nullList = Lists.newArrayList("A", "B", null, "D");
private static final Map<String,String> MAP = ImmutableMap.of("a","A","b","B");
public static void main(String[] args) {
Joiner join = getJoin("@");
System.err.println(joinerList(join));
System.err.println(skillNull());
System.err.println(useNull());
System.err.println(map());
System.err.println(append());
}
private static String joinerList(Joiner join) {
List<String> strings = Lists.newArrayList("a", "b", "c", "d");
return join.join(strings);
}
private static Joiner getJoin(String string) {
return Joiner.on(string);
}
private static String skillNull() {
return getJoin("&").skipNulls().join(nullList);
}
private static String useNull() {
return getJoin("&").useForNull("888").join(nullList);
}
private static String append(){
//append到StringBuilder
StringBuilder stringBuilder = new StringBuilder();
getJoin("#").appendTo(stringBuilder,list);
return stringBuilder.toString();
}
private static String map(){
return getJoin(",").withKeyValueSeparator("=").join(MAP);
}
}
joiner实例总是不可变的。用来定义joiner目标语义的配置方法总会返回一个新的joiner实例。这使得joiner实例都是线程安全的,你可以将其定义为static final常量。
Joiner.MapJoiner
MapJoiner 是 Joiner 的内部静态类,用于帮助将 Map 对象拼接成字符串。
Joiner.on("#").withKeyValueSeparator("=").join(ImmutableMap.of(1, 2, 3, 4));//1=2#3=4
拆分器[Splitter]
JDK内建的字符串拆分工具有一些古怪的特性。比如,String.split悄悄丢弃了尾部的分隔符。 问题:”,a,,b,”.split(“,”)返回?
1. “”, “a”, “”, “b”, “”
2. null, “a”, null, “b”, null
3. “a”, null, “b”
4. “a”, “b”
5. 以上都不对
正确答案是5:””, “a”, “”, “b”。只有尾部的空字符串被忽略了。
从上面的例子中你可以看到String.split方法默认将最后连个空的字符串去除了,在有些情况下你是希望这么做的。但是这样并不是特别好,这样的选择应该留给程序员去处理。Splitter类可以协助去处理这样的情况。 Splitter 类的作用刚好和Joiner相反,Spliter 类可以使用在 字符,固定的字符串,正则表达式,CharMatcher类(下面我们会介绍这个类). 通过调用Splitter类的on方法,可以获取Splitter实例,一旦创建了Splitter类,就可以调用split方法,spliter方法会返回一个包含了结果的可迭代对象.
Splitter.on('|').split("foo|bar|baz");
Splitter splitter = Splitter.on("\\d+");
上面的例子,我们看到一个Splitter实例使用’|’分隔,另外一个splitter使用了一个正则表达式
Splitter 类还有一个选项可以将字符串中的空白字符去除。 效果就想String.split。只要使用 trimResults()
Splitter splitter = Splitter.on('|').trimResults();
就像Joiner类一样,Splitter类是一个不可变类。所以千万不要单独的去调用trimResults方法,这样并不能在原始的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|||");
拆分器工厂
方法 | 描述 | 范例 |
---|---|---|
Splitter.on(char) | 按单个字符拆分 | Splitter.on(‘;’) |
Splitter.on(CharMatcher) | 按字符匹配器拆分 | Splitter.on(CharMatcher.BREAKING_WHITESPACE) |
Splitter.on(String) | 按字符串拆分 | Splitter.on(“, “) |
Splitter.on(Pattern) | Splitter.onPattern(String) | 按正则表达式拆分 Splitter.onPattern(“\r?\n”) |
Splitter.fixedLength(int) | 按固定长度拆分;最后一段可能比给定长度短,但不会为空。 | Splitter.fixedLength(3) |
拆分器修饰符
方法 | 描述 |
---|---|
omitEmptyStrings() | 从结果中自动忽略空字符串 |
trimResults() | 移除结果字符串的前导空白和尾部空白 |
trimResults(CharMatcher) | 给定匹配器,移除结果字符串的前导匹配字符和尾部匹配字符 |
limit(int) | 限制拆分出的字符串数量 |
如果你想要拆分器返回List,只要使用Lists.newArrayList(splitter.split(string))或类似方法。 警告:splitter实例总是不可变的。用来定义splitter目标语义的配置方法总会返回一个新的splitter实例。这使得splitter实例都是线程安全的,你可以将其定义为static final常量。
package strings;
import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Created by LF on 2017/3/6.
*/
public class MySplitter {
public static final String string = "A.A.a.a.b.b.C.C.C..D.D...D,SS.";
public static void main(String[] args) {
sliter3();
}
public static void sliter() {
Splitter splitter = createSplitter(".");
List<String> list = splitter.splitToList(string);
list.forEach(e -> System.err.println(e));
}
public static void sliter2() {
Splitter splitter = createSplitter(".");
List<String> list = splitter.omitEmptyStrings().omitEmptyStrings().splitToList(string);
list.forEach(e -> System.err.println(e));
}
//二级拆分
public static void sliter3() {
String string = "a=b,c=d,e=f";
Splitter splitter = createSplitter(",");
Map<String, String> list = splitter.omitEmptyStrings().omitEmptyStrings().withKeyValueSeparator("=").split(string);
list.forEach((e, e1) -> System.err.println(e + "======" + e1));
}
private static Splitter createSplitter(char a) {
return Splitter.on(a);
}
private static Splitter createSplitter(String a) {
return Splitter.on(a);
}
private static Splitter createSplitter(int a) {
return Splitter.fixedLength(a);
}
private static Splitter createSplitter(Pattern a) {
return Splitter.on(a);
}
private static Splitter createSplitter(CharMatcher a) {
return Splitter.on(a);
}
}
字符匹配器[CharMatcher]
直观上,你可以认为一个CharMatcher实例代表着某一类字符,如数字或空白字符。事实上来说,CharMatcher实例就是对字符的布尔判断——CharMatcher确实也实现了Predicate——但类似”所有空白字符”或”所有小写字母”的需求太普遍了,Guava因此创建了这一API。
然而使用CharMatcher的好处更在于它提供了一系列方法,让你对字符作特定类型的操作:修剪[trim]、折叠[collapse]、移除[remove]、保留[retain]等等。CharMatcher实例首先代表概念1:怎么才算匹配字符?然后它还提供了很多操作概念2:如何处理这些匹配字符?这样的设计使得API复杂度的线性增加可以带来灵活性和功能两方面的增长。
获取字符匹配器的常见方法包括:
方法 | 描述 |
---|---|
anyOf(CharSequence) | 枚举匹配字符。如CharMatcher.anyOf(“aeiou”)匹配小写英语元音 |
is(char) | 给定单一字符匹配。 |
inRange(char, char) | 给定字符范围匹配,如CharMatcher.inRange(‘a’, ‘z’) |
使用字符匹配器
方法 | 描述 |
---|---|
collapseFrom(CharSequence, char) | 把每组连续的匹配字符替换为特定字符。如WHITESPACE.collapseFrom(string, ‘ ‘)把字符串中的连续空白字符替换为单个空格。 |
matchesAllOf(CharSequence) | 测试是否字符序列中的所有字符都匹配。 |
removeFrom(CharSequence) | 从字符序列中移除所有匹配字符。 |
retainFrom(CharSequence) | 在字符序列中保留匹配字符,移除其他字符。 |
trimFrom(CharSequence) | 移除字符序列的前导匹配字符和尾部匹配字符。 |
replaceFrom(CharSequence, CharSequence) | 用特定字符序列替代匹配字符。 |
所有这些方法返回String,除了matchesAllOf返回的是boolean
大小写格式[CaseFormat]
CaseFormat被用来方便地在各种ASCII大小写规范间转换字符串——比如,编程语言的命名规范。CaseFormat支持的格式如下:
格式 | 范例 |
---|---|
LOWER_CAMEL | lowerCamel |
LOWER_HYPHEN | lower-hyphen |
LOWER_UNDERSCORE | lower_underscore |
UPPER_CAMEL | UpperCamel |
UPPER_UNDERSCORE | UPPER_UNDERSCORE |
CaseFormat的用法很直接:
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); // returns "constantName"