使用Joiner类
将任意字符串通过分隔符进行连接到一起是大多程序员经常做的事情。他们经常使用array,list,iterable并且循环变量将每一个临时变量添加到StringBuilder当中去,并且中间添加分隔符。这些笨重的处理方式如下:
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();
}
注意要删除在最后面的分隔符。不是很难懂,但是使用Joiner类可以得到简单的代码模板。同样的例子使用Joiner类代码如下:
public String buildString(List<String> stringList, String delimiter){
return Joiner.on(delimiter).skipNulls().join(stringList);
}
这样更加简明并且不会出错。如果你想将null值替换掉,可以使用如下方法:
Joiner.on("|").useForNull("no value").join(stringList);
使用Joiner类有几点需要注意。Joiner类不仅仅可以处理字符串的array、list、iterable,他还可以处理任何对象的array、list、iterable。结果就是调用每一个元素的toString()方法。因此,如果没有使用skipNulls或者useForNull,就会抛出空指针异常。Joiner对象一旦被创建就是不可变的,所以他们是线程安全的,可以被当作常亮来看待。然后看看下面的代码片段:
  

Joiner stringJoiner = Joiner.on("|").skipNulls();
  //使用useForNull方法将会返回一个新的Joiner实例
  stringJoiner.useForNull("missing");
  stringJoiner.join("foo","bar",null);
在上面的代码实例当中,useForNull方法并没有起作用,null值仍然被忽略了。
Joiner不仅仅能返回字符串,还可以与StringBuilder一起使用:
StringBuilder stringBuilder = new StringBuilder();
Joiner joiner = Joiner.on("|").skipNulls();
//返回的StringBuilder实例当中包含连接完成的字符串
joiner.appendTo(stringBuilder,"foo","bar","baz");
上面的例子,我们传入一个StringBuilder的参数并且返回一个StringBuilder实例。
Joiner类也可以使用实现了Appendable接口的类。
FileWriter fileWriter = new FileWriter(new File("path")):
List<Date> dateList = getDates();
Joiner joiner = Joiner.on("#").useForNulls(" ");
// 返回由字符串拼接后的FileWriter实例
joiner.appendTo(fileWriter,dateList);
这是一个与上一个相似的例子。我们传入一个FileWriter实例和一组数据,就会将这组数据拼接后附加到FileWriter当中并且返回。
我们可以看到,Joiner使一些公共的操作变的非常简单。有一个特殊的方法会实现MapJoiner方法,MapJoiner方法像Joiner一样使用分割符将每组key与value分开,同时key与value之间也有个分隔符。MapJoiner方法的创建如下:
MapJoiner mapJoiner = Joiner.on("#").withKeyValueSeparator("=");
快速回顾一下上面内容:
  • Joiner.on("#")方法会创建一个Joiner的实例。
  • 使用返回的Joiner实例调用withKeyValueSeparator方法将会返回MapJoiner对象。
下面是对MapJoiner方法的单元测试代码:
@Test
public void testMapJoiner() {
  String expectedString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
  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));
}
回顾时间
上面的单元测试开始时创建一个key和value都是字符串的LinkedHashMap实例,值得注意的是我们使用静态工厂方法newLinkedHashMap()来创建,Maps类是在com.google.common. collect包当中。然后使用Joiner类创建一个使用key与value拼接的字符串。最后我们断言他是否与我们期望返回的字符串相同。
 
使用Splitter类
程序员另一个经常处理的问题是对字符串以特定分隔符进行分割并且获取一个字符串数组。如果你需要读取文本文件,你总是会做这样的事情。但是
String.split方法不够完美,看下面的例子:
String testString = "Monday,Tuesday,,Thursday,Friday,,";
//parts is [Monday, Tuesday, , Thursday,Friday]
String[] parts = testString.split(",");
可以看到,String.split方法省略了最后的2个空串。在有些时候,这个做法是你需要的,但是这些事情是应该由程序员来决定是否省略。Splitter类可以帮助我们实现与Joiner类相反的功能。Splitter可以使用单个字符、固定字符串、正则表达式串、正则表达式对象或者CharMatcher对象(另一个Guava的类,本章会讲到)来分割字符串。可以给定具体分割符来创建Splitter对象然后使用。一旦拥有了Splitter实例后就可以调用split方法,并且会返回包含分割后字符串的迭代器对象。
Splitter.on('|').split("foo|bar|baz");
Splitter splitter = Splitter.on("\\d+");
在上面的例子当中,我们看到一个Splitter 实例使用了'|'字符分割,另外一个实例使用了正则表达式进行分割。
Splitter有一个可以处理前面空格和后面空格的方法是trimResults。
//Splits on '|' and removes any leading or trailing whitespace
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 类,像Joiner与MapJoiner一样也有MapSplitter类。MapSplitter类可以将字符串转换成Map实例返回,并且元素的顺序与字符串给定的顺序相同。使用下面方法构造一个MapSplitter实例:
//MapSplitter is defined as an inner class of Splitter
Splitter.MapSplitter mapSplitter = Splitter.on("#"). withKeyValueSeparator("=");
可以看到MapSplitter的创建方式与MapJoiner一样。首先给Splitter指定一个分隔符,然后指定MapSplitter对象key与value的分隔符。下面是一个关于MapSplitter的例子,实现的是与MapJoiner相反地功能。
@Test
public void testSplitter() {
  String startString = "Washington D.C=Redskins#New York City=Giants#Philadelphia=Eagles#Dallas=Cowboys";
  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");
  Splitter.MapSplitter mapSplitter = Splitter.on("#").withKeyValueSeparator("=");
  Map<String,String> splitMap = mapSplitter.split(startSring);
  assertThat(testMap,is(splitMap));
}
 
回顾时间
上面的单元测试是将一个字符串用MapSplitter分割成一个LinkedHashMap的实例。然后断言这个返回的LinkedHashMap实例是否与我们期望是LinkedHashMap实例相同。
Joiners 和Splitters 这两个类应该是每个java开发人员的工具。
 
使用Guava操作字符串
无论你喜欢的哪种语言,所有跟字符串相关的事情都是无聊乏味的并且容易出错。有时候,我们需要从文件或者数据当中读取数据并且重新格式化这些数据提交给用户,或者以固定的格式来保存这些数据。幸运的是,Guava提供给我们非常好用的类使我们操作字符串更加轻松。这些类如下:
  • CharMatcher
  • Charsets
  • Strings
现在我们看一看如何在代码中使用它们。
在第一个例子当中,这个单元测试将会展示使用ASCII类方法来确定一个字符是否是小写。第二个例子将展示将小写字符串转换成大写。
 
使用Charsets类
在java当中,有6个标准字符集在每一个java平台都会被支持。这与经常运行下面代码是相关的:
byte[] bytes = someString.getBytes();
但是有一个问题关于上面的代码。没有指定你想返回字节的字符集,你将会获得系统使用运行时默认的字符集返回的字节,这可能会产生问题有可以默认字符集不是你想要的。所以最佳的做法是像下面这样:
try{
  bytes = "foobarbaz".getBytes("UTF-8");
}catch (UnsupportedEncodingException e){
  //This really can't happen UTF-8 must be supported
}
但是仍然有两个问题在上面的代码当中:
  • UTF-8在java平台 一定会被支持,所以UnsupportedEncodingException一定不会被抛出
  • 一旦我们使用字符串指定字符集的定义,我们可以产生拼写错误然后导致异常抛出。
Charsets类可以帮助我们,Charsets类提供了static final 的六个java平台支持的字符集。使用Charsets类我们可以使上面的例子更简单些:
byte[] bytes2 = "foobarbaz".getBytes(Charsets.UTF_8);
值得注意的是在JAVA7当中,StandardCharsets也提供了同样的功能。现在我们看看Strings类。
 
使用Strings类
Strings类提供一些便利实用的方法处理字符串。你是否写过像下面的代码:
StringBuilder builder = new StringBuilder("foo");
  char c = 'x';
  for(int i=0; i<3; i++){
    builder.append(c);
  }
return builder.toString();
上面例子当中的6行代码我们可以使用一行代码来替换。
Strings.padEnd("foo",6,'x');
第二个参数是很重要的,6指定返回的字符串最小长度为6,而不是指定'x'字符在字符串后面追加多少次。如果提供的字符串长度已经大于了6,则不会进行追加。同样也有一个相类似的padStart方法可以在给定字符串的前面追加字符到指定的长度。
在Strings类当中有三个非常有用的方法来处理空值的:
  • nullToEmpty:这个方法接受一个字符串参数,如果传入的参数不是null值或者长度大于0则原样返回,否则返回空串("");
  • emptyToNull:这个方法类似于nullToEmpty,它将返回null值如果传入的参数是空串或者null。
  • isNullOrEmpty:这个方法会检查传入参数是否为null和长度,如果是null和长度为0就返回true。
或许,这将是一个不错的主意总是在任何使用nullToEmpty方法处理传入的字符串参数。
 
使用CharMatcher类
CharMatcher提供了在一定字符串中匹配是否存在特定字符串的功能。在CharMatcher类当中的方法也可以让格式化更加简单。例如,你可以将多行的字符串格式化成一行,并且换行符将会以空格来代替。
CharMatcher.BREAKING_WHITESPACE.replaceFrom(stringWithLinebreaks,' ');
还有一个版本replaceFrom的,需要一个CharSequence的值作为第2个参数值,而不是一个单一的字符。
移除多个空格和tab以单个空格来代替,代码如下:
@Test
public void testRemoveWhiteSpace(){
  String tabsAndSpaces = "String with spaces and tabs";
  String expected = "String with spaces and tabs";
  String scrubbed = CharMatcher.WHITESPACE.collapseFrom(tabsAndSpaces,' ');
  assertThat(scrubbed,is(expected));
}
在上面的测试代码中,我们把所有多个空格和tab都替换成了一个空格,所有都在一行上。
上面例子在某些情况下可行,但是如果字符串在开头就有空格我们想移除怎么办?返回的字符串当中前面依然会包含空格,这时可以使用trimAndCollapseFrom方法:
@Test
public void testTrimRemoveWhiteSpace(){
  String tabsAndSpaces = " String with spaces and tabs";
  String expected = "String with spaces and tabs";
  String scrubbed = CharMatcher.WHITESPACE. trimAndCollapseFrom(tabsAndSpaces,' ');
  assertThat(scrubbed,is(expected));
}
在这个测试当中,我们再一次将把多个空格和tab替换成一个空格也在一行上。
列出所有在CharMatcher类可用的方法是不切实际的,这里是不是更换一组匹配字符的地方,我们保留所匹配的字符的例子: 
@Test
public void retainFromTest()
{
String lettersAndNumbers = "foo989yxbar234";
String expected = "989234";
String actual = CharMatcher.JAVA_DIGIT.retainFrom(lettersAndNumbers);
assertEquals(expected, actual);
}
在这个例子当中我们找到"foo989yxbar234"字符串当中所以的数字并且保留下来。
往下继续之前,我们应该看看最后一个CharMatcher类中的强大功能。可以联合多个CharMatcher类实例创建一个新的CharMatcher类实例。
假设你需要创一个匹配数字和空格的CharMatcher类实例:
CharMatcher cm = CharMatcher.JAVA_DIGIT.or(CharMatcher.WHITESPACE);
它现在将会匹配任何数字或者空格。CharMatcher类对于操作字符串来说功能强大并且很好用。
 
使用Preconditions类
Preconditions类是用来验证我们的代码状态的静态方法的集合。 Preconditions非常重要,因为他们保证我们的期望执行成功的代码得到满足。 如果条件与我们期望的不同,我们会及时反馈问题。和以前一样,使用前提条件的重要性是确保我们代码的行为,并在调试中很有用。
你可以写你自己的先决条件,像下面这样:
if(someObj == null){
throw new IllegalArgumentException(" someObj must not be null");
}
使用Preconditions当中的方法(需要静态导入),检查一个空值更简单。
checkNotNull(someObj,"someObj must not be null");
接下来,我们将要展示使用先决条件的例子:
public class PreconditionExample {
  private String label;
  private int[] values = new int[5];
  private int currentIndex;
  public PreconditionExample(String label) {
    //返回label如果不为空
    this.label = checkNotNull(label,"Label can''t be null");
  }
  public void updateCurrentIndexValue(int index, int valueToSet) {
    //检查索引是否有效
    this.currentIndex = checkElementIndex(index, values.length, "Index out of bounds for values");
    //检查参数值
    checkArgument(valueToSet <= 100,"Value can't be more than 100");
    values[this.currentIndex] = valueToSet;
  }
  public void doOperation(){
    checkState(validateObjectState(),"Can't perform operation");
  }
  private boolean validateObjectState(){
    return this.label.equalsIgnoreCase("open") && values[this.
    currentIndex]==10;
  }
}
下面是对上面例子当中四个方法的摘要信息:
  • checkNotNull(T object, Object message):这个方法如果object不为null直接返回,如果为null会抛出空指针异常。
  • checkElementIndex (int index, int size, Object message):在这方法当中,index是你将要访问的元素下标,size是这个要访问的array,list或者字符串的长度。然后校验是否有效,如果无效抛出IndexOutOfBoundsException。
  • checkArgument (Boolean expression, Object message):这方法传入布尔表达式。 这个布尔表达式如果为true则继续执行,否则抛出IllegalArgumentException。
  • checkState (Boolean expression, Object message):这方法传入 一个布尔表达式涉及对象的状态,而不是参数。 这个布尔表达式如果为true则继续执行,否则抛出IllegalArgumentException。
Object工具
在这个章节当中我们将介绍帮助检查null值和创建toString和hashCode的方法的实用方法。我们接着去看看一个有用的类,它实现Comparable接口。 
 
Getting help with the toString method
当我们要调试的时候,toString方法是必须重写的,重写它的乏味无趣的。然而,Objects类可以使用toStringHelper方法让重写更简单。看下面的例子:
public class Book implements Comparable<Book> {
  private Person author;
  private String title;
  private String publisher;
  private String isbn;
  private double price;
  public String toString() {
    return Objects.toStringHelper(this).omitNullValues().add("title", title).add("author", author).add("publisher", publisher)
        .add("price",price).add("isbn", isbn).toString();
  }
让我们看看toString方法:
  • 首先我们传入一个Book对象来创建一个Objects.ToStringHelper实例。
  • 第二步,我们调用omitNullValues来排除任何null值的属性。
  • 调用add方法来添加每一个属性的标签和属性。
检查null
firstNonNull方法接受2个参数并且返回第一个参数如果它不为null。
String value = Objects.firstNonNull(someString, "default value");
firstNonNull方法使用时候如果你不确定传入的值是否为null你可以提供一个默认值给它。需要注意:如果传入的2个参数都是null,会抛出空指针异常。
 
创建hash codes
为类写hashCode方法是基本的但是乏味无趣。Objects类可以帮助我们使用hashCode方法更加简单。考虑下Book类有4个属性:title, author, publisher, 和isbn. 下面的代码将展示使用Object.hashCode方法返回hashCode值。
public int hashCode() {
  return Objects.hashCode(title, author, publisher, isbn);
}
实现CompareTo方法
再次使用Book类,下面是典型的实现compareTo方法。
public int compareTo(Book o) {
  int result = this.title.compareTo(o.getTitle());
  if (result != 0) {
    return result;
  }
  result = this.author.compareTo(o.getAuthor());
  if (result != 0) {
    return result;
  }
  result = this.publisher.compareTo(o.getPublisher());
  if(result !=0 ) {
    return result;
  }
  return this.isbn.compareTo(o.getIsbn());
}
现在让我们看一看使用ComparisonChain类来实现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();
}
第二个例子显得更紧凑和更好阅读。而且,ComparisonChain类会在第一个比较当中如果返回非零时停止比较,只有一种情况返回0,那就是所有的比较返回的都是0。
 
概要
在本章中我们介绍了许多基础操作。我们学习了如何使用Guava让分割字符串更简单通过使用Joiner, Splitter,和非常有用的MapJoiner和MapSplitter类。我们也学习了使用Charsets, CharMatcher, 和 Strings 来操作字符串。
我们学习了如何让我们代码更加强壮和便于调试通过使用Preconditions类。在Objects类中,我们学习了一些使用方法来设置默认值和创建toString和hashCode方法。我们也学习了使用ComparisonChain类来实现compareTo方法更简单。
在下一章,我们学习如何使用Guava来进行函数式编程,通过Function和Predicate接口使我们的编程效率更加高。

 

基本Guava工具的更多相关文章

  1. 强大的 Guava 工具类

    Java 开发的同学应该都使用或者听说过 Google 提供的 Guava 工具包.日常使用最多的肯定是集合相关的工具类,还有 Guava cache,除了这些之外 Guava 还提供了很多有用的功能 ...

  2. 工具篇:介绍几个好用的guava工具类

    前言 平时我们都会封装一些处理缓存或其他的小工具.但每个人都封装一次,重复造轮子,有点费时间.有没有一些好的工具库推荐-guava.guava是谷歌基于java封装好的开源库,它的性能.实用性,比我们 ...

  3. Google的Guava工具类splitter和apache stringutil对比 编辑

    一直用的是apache的stringutil工具类,其实google的工具类项目 guava中居然也有字符串的分隔类splitter的,在 http://code.google.com/p/guava ...

  4. [转]基本Guava工具

    转自:http://www.cnblogs.com/renchunxiao/p/3661918.html?utm_source=tuicool 使用Joiner类 将任意字符串通过分隔符进行连接到一起 ...

  5. Guava工具类

    原文链接:http://blog.csdn.net/mnmlist/article/details/53425865 Objects类 Objects类有几个比较不错的方法,toString.hash ...

  6. Google guava工具类的介绍和使用

    概述 工具类 就是封装平常用的方法,不需要你重复造轮子,节省开发人员时间,提高工作效率.谷歌作为大公司,当然会从日常的工作中提取中很多高效率的方法出来.所以就诞生了guava.. 高效设计良好的API ...

  7. Guava工具类学习

    目录 一.介绍 二.Optional类 1.定义 2.java8自带Optional 3.使用 三.Preconditions类 1.定义 2.使用 四.Ordering类 1.定义 2.使用 五.R ...

  8. Guava 工具类之Cache的使用

    一.guava cache 介绍 1.介绍 guava cache是Google guava中提供的一款轻量级的本地缓存组件,其特点是简单.轻便.完善.扩展性强,内存管理机制也相对完善. 2.使用缓存 ...

  9. Guava 工具类之 Splitter的使用

    Splitter可以对字符串进行分割,在分割时的方式有2种, 1.按字符/字符串分割 2.按正则进行分割 Splitter在分割完成时可以转换成list和map 一.按字符进行分割 //1.用指定字符 ...

随机推荐

  1. ThinkPHP神秘应用架构扩展

    ThinkPHP应用模式提供了机会,改变核心框架.它可以让你的应用程序,以适应环境和其他许多不同的需求. 每一个应用模式都有自己的模式定义文件,相对与ThinkPHP3.1版本号.ThinkPHP3. ...

  2. SVN & Git (一)

    (一)SVN的使用.CornerStone图形化管理工具! SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. ...

  3. MapReduce的InputFormat学习过程

    昨天,经过几个小时的学习.该MapReduce学习的某一位的方法的第一阶段.即当大多数文件的开头的Data至key-value制图.那是,InputFormat的过程.虽说过程不是非常难,可是也存在非 ...

  4. 互联网创业应该如何找到创意 - RethinkDB创始人Slava Akhmechet的几点建议

    关于作者 我叫Slava Akhmechet,本人是 RethinkDB 的创始人之一,RethinkDB是一个设计来帮助开发者和运营团队来处理无结构数据的一个开源的分布式数据库,用户可以使用它来作为 ...

  5. 苹果浏览器Safari对JS函数库中newDate()函数中的参数的解析中不支持形如“2020-01-01”形式

    苹果浏览器safari对new Date('1937-01-01')不支持,用.replace(/-/g, "/")函数替换掉中划线即可 如果不做处理,会报错:invalid da ...

  6. sql点滴40—mysql乱码问题总结

    原文:sql点滴40-mysql乱码问题总结 本文将为大家讲解如何处理Java连接过程中的MySQL中文乱码问题.一般MySQL中文乱码问题都是与字符集有关,这里作者的经历也大致差不多. MySQL默 ...

  7. Callback

    由于 JavaScript 语句(指令)是逐一执行的 - 按照次序,动画之后的语句可能会产生错误或页面冲突,因为动画还没有完成. 为了避免这个情况,您可以以参数的形式添加 Callback 函数. j ...

  8. GIMP也疯狂之动态图的制作(二)

    首先看下效果: (素材丢失,无法提供) 所用工具:GIMP.GIMP-GAP(在源中直接搜索安装) 文后会添加一个从U2B上搬运过来的视频教程,效果不错,值得一看本想也制作个人物变换,但几次实验,相同 ...

  9. Spring IOC之 使用JSR 330标准注解

    从Spring 3.0开始,Spring提供了对 JSR 330标准注解的支持.这些注解可以喝Spring注解一样被扫描到.你只需要将相关的Jar包加入到你的classpath中即可. 注意:如果你使 ...

  10. 题目要求:建立一个类Str,将一个正整数转换成相应的字符串,例如整数3456转换为字符串"3456".

    题目要求:建立一个类Str,将一个正整数转换成相应的字符串,例如整数3456转换为字符串"3456". 关键:怎么将一个数字转换为字符? [cpp] view plaincopy ...