Java
里字符串表示字符的不可变序列,建立后就不能更改。在咱们平常的工做中,字符串的使用很是频繁,熟练的对其操做能够极大的提高咱们的工做效率,今天要介绍的主角是 Google
开源的一个核心 Java
库 Guava,它提供了集合类型、不可变的集合、并发、I / O、缓存、字符串等许多实用功能。在本文中,咱们将学习使用 Guava
中的 Strings
和 Splitter
字符串操做工具类。html
Google Guava
会同步到 Maven Central 中,因此,若是你是 Maven
项目的话只须要在 pom.xml
文件中引入以下依赖便可:java
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.2-jre</version> </dependency>
对于 Gradle
项目在 build.gradle
中引入以下依赖便可:git
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
<!--more-->github
PS:28.2-jre 是编写本文时的最新版本,你能够从
Maven Central 中查看当前的最新版本。
正则表达式
Google Guava
提供了不少实用的静态方法,这些能够解决开发人员在开发中所要完成的一些重复任务。固然,这个工做咱们也能够本身作,可是引入类库它会下降错误发生的可能性,毕竟这些类库都是已经通过多年的生产验证。好比类库中 Strings
提供的一个方法 commonPrefix
,它接受两个字符串并返回两个字符串之间的公共前缀(eg: abcd
和 abef
返回 ab
)。你能够在脑子里想象一下在应用程序代码中面临这样的要求时,本身要如何编写代码来完成该操做,要本身实现这个功能,仍是须要花费一些时间的,同时还须要考虑到各类边界异常状况。这就是类库提供给咱们的最大价值之一,因此当咱们须要的某种功能能够做为一种工具方法使用时,首先应该去寻找一些已存在的类库并去熟练使用的它们,而不是本身去实现。总结起来使用类库有以下几个缘由:缓存
Google Guava
类库有人已经对其进行了完全的测试,bug
出现的几率会比咱们本身实现的小不少Google Guava
的一部分,已经存在各类测试用例,用于测试实用程序的实现。若是咱们本身编写代码实现的话,可能还要去编写和维护它们的测试。Google Guava
有许多实用的工具类和方法,不可能在一篇文章中都有介绍完,在本文中,只会介绍和字符串操做相关的两个工具类。首先第一个是 Strings
类,该类提供了操做 String
和 CharSequence
的实用方法。并发
nullToEmpty
方法功能为:若是传入的字符串为 null
,则返回一个空字符串 ""
,不然,返回一个空字符串,不然按原样返回传递的字符串。工具
@Test public void testStringsOfNullToEmpty() { System.out.println(Strings.nullToEmpty("mghio")); // mghio System.out.println(Strings.nullToEmpty("")); // "" System.out.println(Strings.nullToEmpty(null)); // "" System.out.println(Strings.nullToEmpty(null).isEmpty()); // true }
emptyToNull
方法功能为:它与 nullToEmpty
相反,若是传入了空字符串,则返回 null
,不然返回原始字符串。学习
@Test public void testStringsOfEmptyToNull() { System.out.println(Strings.emptyToNull("mghio")); // mghio System.out.println(Strings.emptyToNull(null)); // null System.out.println(Strings.emptyToNull("")); // null }
isNullOrEmpty
方法功能为:若是传入的字符串为 null
或为空,则返回 true
,不然返回 false
。测试
@Test public void testStringsOfIsNullOrEmpty() { System.out.println(Strings.isNullOrEmpty("mghio")); // false System.out.println(Strings.isNullOrEmpty("")); // true System.out.println(Strings.isNullOrEmpty(null)); // true }
这两个方法有三个参数,分别为:输入字符串、最小长度和要填充的字符,它将字符根据须要屡次插入到输入字符串的开头,以使输入字符串的长度等于传入的最小长度。
@Test public void testStringsOfPadStart() { System.out.println(Strings.padStart("9527", 6, '0')); // 009527 System.out.println(Strings.padStart("123456", 6, '0')); // 123456 }
在第一行代码中,将两次填充 0
以使最终的字符串长度等于咱们传入的最小长度(6)。在第二行代码中,输入字符串长度自己具备所需的最小长度,所以未进行填充padEnd
方法和上面这个方法相似,只不过它是在字符的末尾而不是在开始处进行填充。
@Test public void testStringsOfPadEnd() { System.out.println(Strings.padEnd("9527", 6, '0')); // 952700 System.out.println(Strings.padEnd("123456", 6, '0')); // 123456 }
该方法须要传入一个字符串和一个重复次数 count
,它返回一个由原始字符串组成的字符串,该字符串重复了 count
次。
@Test public void testStringsRepeat() { System.out.println(Strings.repeat("mghio", 3)); // mghiomghiomghio }
commonPrefix
方法返回传入的两个字符串之间最大的公共前缀,而 commonSuffix
方法返回传入两个字符串之间最大的公共后缀。
@Test public void testStrings() { System.out.println(Strings.commonPrefix("mghio9527", "mghio666")); // mghio System.out.println(Strings.commonSuffix("iammghio", "nicemghio")); // mghio }
Splitter
类提供的功能正如其名(PS:一个好的命名很重要
),它用于根据提供的分割符将字符串拆分为多个子字符串。咱们能够经过传入一个分割符来获一个 Splitter
的实例,有了分割器以后,咱们能够根据分割器的配置方式对字符串进行分割。
@Test public void testSplitterOfSplit() { Iterable<String> result = Splitter.on(",").split("m,g,h,i,o"); System.out.println(result); // [m, g, h, i, o] }
上面的例子中使用逗号进行分割,所以,它将传入的字符串 m,g,h,i,o
拆分为一个 Iterable <String>
,而后当咱们对其进行迭代遍历时会输出 [m, g, h, i, o]
。
如今,咱们来看看得到一个分割器 Splitter
的各类方法。on
方法有各类不一样的重载版本,它们以字符、字符串或正则表达式做为分隔符,咱们还能够将 Pattern
实例做为字符串传递给 onPattern
方法中。
@Test public void testSplitterOfOn() { Splitter wordSplitter = Splitter.on(":;"); // 下面这行输出结果 [the, text, is, separated, by, colon, semicolon] System.out.println(wordSplitter.split("the:;text:;is:;separated:;by:;colon:;semicolon")); Splitter patternBasedSplitter = Splitter.on(Pattern.compile("\\s+")); System.out.println(patternBasedSplitter.split("abc dmg hio")); // [abc, dmg, hio] System.out.println(Splitter.onPattern("\\s+").split("www mghio cn")); // [www, mghio, cn] }
fixedLength
也是最有用的方法之一,它能够将字符串分红给定长度的相等部分,须要注意的是,最后一个部分可能会小于给定的长度。
@Test public void testSplitterOfFixedLength() { Splitter fixedLengthSplitter = Splitter.fixedLength(3); System.out.println(fixedLengthSplitter.split("iammghiojava")); // [iam, mgh, ioj, ava] System.out.println(fixedLengthSplitter.split("https://www.mghio.cn")); // [htt, ps:, //w, ww., mgh, io., cn] }
Splitter
还提供了能够在更改或修改 Splitter
行为的经常使用方法。
这个方法能够从生成的分割器的结果字符串中删除前面和末尾的空格。
@Test public void testSplitterOfTrimResult() { Splitter commaSplitter = Splitter.on(","); System.out.println(commaSplitter.split("m, g, h, i, o")); // [m, g, h, i, o] Splitter commaSplitterWithTrim = commaSplitter.trimResults(); System.out.println(commaSplitterWithTrim.split("m, g, h, i, o")); // [m, g, h, i, o] }
注意,第一个分割的结果在字符串 g
、 h
、i
、o
以前有一个空格,使用 trimResults
方法后,将去除这些前导空格。
这个方法会从结果中忽略全部空字符串。
@Test public void testSplitterOfOmitEmptyStrings() { Splitter commaSplitter = Splitter.on(","); System.out.println(commaSplitter.split("m,,g,h,i,o")); // [m, , g, h, i, o] Splitter commaSplitterWithNoEmptyString = commaSplitter.omitEmptyStrings(); System.out.println(commaSplitterWithNoEmptyString.split("m,,g,h,i,o")); // [m, g, h, i, o] }
上面的 commaSplitterWithNoEmptyString
会从输出中删除空字符串的结果。
这个方法返回与原始分割器等效的分割器,但它会在达到指定的输入限制后将中止拆分,将后续剩余结果字符串做为一项输出,也就是说,咱们能够经过的传入的参数指定结果中存在的最大项目数。须要注意的是:该方法在省略空字符串时,省略的字符串不计算在内。
。
@Test public void testSplitterOfLimit() { Splitter commaSplitter = Splitter.on(","); Splitter limitingCommaSplitter = commaSplitter.limit(3); System.out.println(limitingCommaSplitter.split("i,m,g,h,i,o")); // [i, m, g,h,i,o] }
有一点须要注意,Splitter
是不可变的(这一点和 String
相似),所以,调用它的任何修饰符方法都将返回新的 Splitter
,而且不会修改原始的 Splitter
。
@Test public void testSplitterImmutable() { Splitter splitter = Splitter.on('/'); System.out.println("Before: " + splitter); // Before: com.google.common.base.Splitter@33b37288 splitter.trimResults(); // do nothing System.out.println("First: " + splitter); // First: com.google.common.base.Splitter@33b37288 splitter = splitter.trimResults(); // the returned splitter to be assigned System.out.println("Second: " + splitter); // Second: com.google.common.base.Splitter@77a57272 }
咱们前面已经使用的 split
方法,它返回的是一个 Iterable<String>
对象。而这里的 splitToList
方法返回一个 List<String>
。因为分割方法返回的是 Iterable
,所以它是惰性
的。
@Test public void testSplitterOfSplitToList() { Splitter commaSplitter = Splitter.on(","); List<String> result = commaSplitter.splitToList("m,g,h,i,o"); System.out.println(result); // [m, g, h, i, o] }
MapSplitter
顾名思义就是用来将一个将字符串拆分为 Map
对象的。咱们可使用 withKeyValueSeparator
方法从 Splitter
中获取 MapSplitter
对象,该方法接收一个字符、字符串或者 Splitter
对象做为参数。首先,根据原始的分割器将字符串分割为多个项,而后,使用传给 withKeyValueSeparator
方法的分割符将各个项分为 Map
键-值对。
@Test public void testSplitterOfWithKeyValueSeparator() { Splitter commaSplitter = Splitter.on(','); Splitter.MapSplitter keyValueSplitter = commaSplitter.withKeyValueSeparator('='); Map<String, String> map = keyValueSplitter.split("name=mghio,blog=mghio.cn"); System.out.println(map); // {name=mghio, blog=mghio.cn} }
从结果能够看到,它分割为两个 entry
(name=mghio
与 blog=mghio.cn
)项,还有一个点须要注意的是:若是咱们在原始的分割器上指定了任何修改器,则它们仅适用于该分割器,而不适用于 MapSplitter
。
@Test public void testSplitterOfWithKeyValueSeparatorAndModifiers() { Splitter originalSplitter = Splitter.on(",").trimResults(); Splitter.MapSplitter keyValueSplitter = originalSplitter.withKeyValueSeparator('='); // 输出结果:{name =mghio, blog= mghio.cn} System.out.println(keyValueSplitter.split("name =mghio, blog= mghio.cn")); }
由以上结果能够看出 trimResults
修饰方法仅适用于原始拆分器。所以,blog
开头的空格已被移除(使用 ,
分割原始字符串时),可是,mghio.cn
开头的空格不会被移除(使用 =
分割成键值时)。
最后须要注意的是:MapSplitter
类被标记为 @Beta
,这意味着类库中与 MapSplitter
相关的类和方法是实验性的,能够更改(以中断的方式),甚至未来版本可能删除。
在本文中,介绍了 Google Guava 库以及在项目或应用程序中使用它的好处,如何将其导入到咱们的应用程序中使用。而后,介绍了 Guava
库中对字符串操做工具类(Strings
和 Splitter
)的一些基本用法,固然,这只是冰山一角,Guava
库还提供了其它不少有用的基础功能,须要咱们本身去查询相关文档学习了解,感兴趣的朋友能够去看看它的实现源码,这个库的代码写得很优雅。
参考