作者:Jack47

转载请保留作者和原文出处

欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源

本文是我写的Google开源的Java编程库Guava系列之一,主要介绍Guava中提供的很多小工具类,这些类让Java语言用起来更舒畅。

使用或者避免null值##

null引用的发明者Sir C.A.R.Hoare(也是快排算法的发明者)把null称之为十亿美元错误。Guava的开发者们通过研究Google的代码发现95%的集合中都不需要支持为null的值,所以对于开发者而言,遇到null时需要快速失败而不是默默地接受nullnull的含义在大部分场景下都不够清晰,例如Map.get(key)返回null时,可能是因为map中的值就是null,或者map中没有这个key。但null在有些情况下也很有用,从内存和性能方面来看,null很廉价,在使用对象数组,是不可避免的要用到null的。综合考虑之后,Guava库中绝大部分工具都被设计成遇到null时快速失败。

Optional

如果程序员需要使用null来表示不存在的情况,那么Optional<T>就能派上用场了。Optional<T>是用非null的值来代替一个可能为null的值。举个例子:

Optional<Integer> possible = Optional.of(null);
boolean isPresent = possible.isPresent(); // returns false

再看这个例子:

Optional<Integer> possible = Optional.of(5);
boolean isPresent = possible.isPresent(); // returns true
possible.get(); // returns 5

聪明的读者已经发现了,Optional是一个容器对象,它可能容纳一个非null的值,也可能没有值。如果这个值存在,isPresent()函数会返回true而且get()函数会返回这个值。

引入Optional类除了因为给null一个有意义的名字而增加了可读性外,最大的好处是Optional能够强制你主动思考程序中值不存在的情况,而null是很容易被忽略的。如果值不存在,想使用默认值,可以使用Optional中提供的T or(T)函数,例如:

Optional<Integer> default = Optional.of(0);
Optional possible = Optional.of(field);
return possible.or(default)

如果field为null,那么返回值就是default,调用者需要先判断值是否存在isPresent(),如果存在,再拿到值get()

Strings类提供了值可能为null的一些函数,例如:

boolean invalid = Strings.isNullOrEmpty(res);
String name = Strings.emptyToNull(passedName);

Preconditions(先决条件)##

Preconditions类中提供了几个非常实用的静态函数来帮助检查调用函数或构造函数时的先决条件是否满足。这些函数都接受一个boolean类型的表达式,如果表达式为false,会抛出一个非受检异常,来通知调用方发生了调用错误。

Preconditions类的目的是提高代码的可读性,例如checkArgument(i >=0 , "Argument was %s but expected nonnegative", i);,一看就知道是在检查传入的参数;this.field = checkNotNull(field),是检查field字段不为空。这里需要注意提供的错误信息需要清晰有效。

对象的通用函数##

使用这些函数能够简化实现对象函数的过程,例如hashCode()toString()函数

equal函数###

如果对象内部变量可以为null,实现equal函数有些费劲,因为需要单独检查nullObjects.equal函数已经实现了对null敏感的检查,不会出现NullPointerException的异常。

Objects.equal("a", "a"); //returns true
Objects.equal(null, "a"); // returns false
Objects.equal(null, null); // returns true

注:最新的JDK 7里引入了Ojbects类,提供了同样的函数。

hashCode函数###

平常实现hashCode函数是不是很痛苦?如果类内部的成员变量较多,代码就会比较冗长。Guava提供了Objects.hashCode(field1, field2,...,fieldn)的函数,它能够对指定顺序的多个字段进行哈希,这样就不用自己手工实现一遍对各个字段进行哈希的过程了。举个栗子:

return Objects.hashCode(name, address, url);

toString函数

toString在日志和调试中发挥巨大威力,但是实现起来很麻烦,需要注意各个有用字段输出时的组织格式。来看看MoreObjects.toStringHelper如何让整个过程变的简单:

// return "MyObject{x=1,y=2}
Objects.toStringHelper(this)
.add("x", 1)
.add("y", 2)
.toString();

compare/compareTo函数

实现比较器(Comparator),或者实现Comparable接口时,通常需要对类内部的所有成员变量进行比较,实现起来很麻烦。Guava提供了ComparisonChain类,它能够进行"懒"比较:只有当发现为0的结果,才会继续后面的结果,不然就忽略后续的比较。举个例子:

public int compareTo(Foo other) {
return ComparisonChain.start()
.compare(this.x, other.x)
.compare(this.y, other.y)
.result();
}

Ordering

Guava提供了一个流畅型(fluent)的比较器(Comparator)类:Ordering,它提供了链条函数来微调或者增强已有的比较器,或者构造复杂的比较器,应用到对象的集合上。

Ordering的核心是一个Comparator实例。使用已有的比较器来构造一个Ordering实例:

Ordering<Item> ordering = Ordering.from(Comparator<Item> comparator);

也可以使用自然顺序: Ordering<T>.natural()

或者自己实现一个Ordering类,只需要继承并实现compare()函数就可以。

Ordering进行微调:

reverse()
compound(Comparator)
onResultOf(Function)
nullsFirst()

由于Ordering类继承自Comparator,所以在任何需要Comparator的地方,都可以使用Ordering代替,同时Ordering提供了一些操作:

immutableSortedCopy()
isOrdered()/ isStrictlyOrdered()
min()

字符串相关的函数

合并(Joiner)

流畅风格的Joiner提供了使用分隔符把一些字符串序列合并到一起的功能。例如:

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

如果不想跳过值为null的字符串,想用某个特定字符串代替null,可以使用函数useForNull(String)

Joiner类也可以用在其他对象类型上,此时会使用对象的toString()函数得到字符串,然后进行合并。

切分(Splitter)

Java的字符串分割函数有一些诡异的行为,例如String.split()函数会默默地把尾部的分隔符丢弃掉。而使用Splitter的好处在于可以完整地显示地控制这些行为。Splitter类可以用来在任意的Pattern, char, String或者CharMatcher上进行分割。举个例子:

// returns ["foo", " bar", "", "   qux", ""]
Splitter.on(',').split("foo, bar,, qux,");

Splitter还提供了其他的配置函数来对合并过程进行定制:omitEmptyStrings(),trimResults(), limit()等。例如对于上面的例子,如果想忽略空字符串,让结果中去掉开头和结尾的空格,可以这样做:

// returns ["foo","bar","qux"]
Splitter.on(',')
.trimReults()
.omitEmptyStrings()
.split("foo, bar,, qux,");

注意:SplitterJoiner实例都是不可变的(immutable),所以SplitterJoiner都是线程安全的,可以声明为static final的常量来使用。他们的配置函数都是返回一个新的Splitter实例,此时需要使用返回的新的Splitter的实例。

字符匹配(Character Matchers)

CharMatcher类的设计思想很巧妙,定义两个基本属性,然后任意组合他们。这样API的复杂度是线性增加的,但是灵活性和功能是平方式增强的。

CharMatcher定义的两个属性:

  1. 需要匹配什么样的字符串?
  2. 在这些匹配的字符串上执行什么样的操作?例如 trimming,collapsing, removing等。

一些例子:

	// remove control characters
String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(inputString);
// only the digits
String theDigits = CharMatcher.DIGIT.retainFrom(inputString);
// eliminate all characters that aren't digits or lowercase
String lowerAndDigit = CharMatcher.JAVA_DIGIT.or(CharMatcher.JAVA_LOWER_CASE).retainFrom(inputString);
// trim whitespace and replace/collapse whitespace into single spaces
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(inputString, ' ');

认真的读者通过看上面的例子会发现CharMatcher已经提供了很多现成的匹配特定字符串的常量,例如WHITESPACE,JAVA_DIGIT等。也可以通过其他几个函数来构造匹配特定字符串的CharMatcher:

is(char);
isNot(char);
negate()
inRange(char, char)
or(CharMatcher);
and(CharMatcher);

可以在CharMatcher上执行的操作

boolean matchesAllOf(CharSequence)
boolean matchesAnyOf(CharSequence)
boolean matchesNoneOf(CharSequence)
int indexIn(CharSequence, int)
int countIn(CharSequence)
String removeFrom(CharSequence)
String retainFrom(CharSequence)
String trimFrom(CharSequence)
String replaceFrom(CharSequence, char)

Charsets

Charsets类提供了Java平台的所有实现中都支持的六个标准的字符集的常量引用。所以不要这样做:

try {
bytes = content.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AssertionError(e);
}

而是用下面的代码替代:

bytes = content.getBytes(Charsets.UTF_8);

注:JDK7中StandardCharsets类已经实现了同样功能

基本类型相关的函数

Java中Arrays类提供了众多对数组进行操作的函数,基础类型对应的包装类例如Integer,也提供了很多使用函数。而Guava为Java中的8个基本类型提供了其他一些非常实用的函数,例如数组和集合相关的API,从类型转换到byte数组的表示方式等。

例如:

int[] content = {1,3,4};
Ints.indexOf(content, 3); // 1
Ints.concat(new int[] {1,2}, new int[]{3, 4}) // 1,2,3,4
Ints.contains(new int[]{10,20,30,40}, 20) // true
Ints.min(10,20,30,40) // 10
byte[] bytes = Ints.toByteArray(integer);

回到本系列目录: Google Java编程库Guava介绍


如果您看了本篇博客,觉得对您有所收获,请点击右下角的“推荐”,让更多人看到!

资助Jack47写作,打赏一个鸡蛋灌饼钱吧
微信打赏
支付宝打赏

Guava库介绍之实用工具类的更多相关文章

  1. C++ 之Boost 实用工具类及简单使用

    本文将介绍几个 Boost 实用工具类,包括 tuple.static_assert.pool.random 和 program_options等等.需要对标准 STL 具备一定的了解才能充分理解本文 ...

  2. 重复造轮子,编写一个轻量级的异步写日志的实用工具类(LogAsyncWriter)

    一说到写日志,大家可能推荐一堆的开源日志框架,如:Log4Net.NLog,这些日志框架确实也不错,比较强大也比较灵活,但也正因为又强大又灵活,导致我们使用他们时需要引用一些DLL,同时还要学习各种用 ...

  3. java Http消息传递之POST和GET两种方法--通过实用工具类来获取服务器资源

    实现该方法需要导入一些jar包 可以去一下地址下载: http://pan.baidu.com/s/1hqrJF7m /** * 实用工具类来获取服务器资源 * * get方法传送数据 * * 1.通 ...

  4. Java日期时间实用工具类

    Java日期时间实用工具类 1.Date (java.util.Date)    Date();        以当前时间构造一个Date对象    Date(long);        构造函数   ...

  5. [Google Guava] 2.4-集合扩展工具类

    原文链接 译文链接 译者:沈义扬,校对:丁一 简介 有时候你需要实现自己的集合扩展.也许你想要在元素被添加到列表时增加特定的行为,或者你想实现一个Iterable,其底层实际上是遍历数据库查询的结果集 ...

  6. Guava库介绍之集合(Collection)相关的API

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文是我写的Google开源的Java编程库Guava系列之一,主要介 ...

  7. [Guava学习笔记]Collections: 集合工具类

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3861431.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  8. 实用工具类--第三方开源--Lazy

    下载地址 :https://github.com/ddwhan0123/Lazy 工具 描述 AnimationUtils 动画工具类 AppUtils APP相关信息工具类 AssetDatabas ...

  9. SpringMvc 中的实用工具类介绍(包括 ResponseEntity、 RestTemplate、WebUtils 等)

    此部分内容将包含 ResponseEntity. RestTemplate.WebUtils 等 1. ResponseEntity ① Sprring Mvc 中作为方法的返回值使用法 @Reque ...

随机推荐

  1. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  2. 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)

           首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...

  3. HTML5 语义元素(一)页面结构

    本篇主要介绍HTML5增加的语义元素中关于页面结构方面的,包含: <article>.<aside>.<figure>.<figcaption>.< ...

  4. H5坦克大战之【画出坦克】

    今天是个特殊的日子,圣诞节,也是周末,在这里先祝大家圣诞快乐!喜庆的日子,我们可以稍微放松一下,扯一扯昨天雷霆对战凯尔特人的比赛,这场比赛大威少又双叒叕拿下三双,而且是一个45+11+11的超级三双, ...

  5. 多线程 异步 beginInvoke EndInvoke 使用

    有许多耗时操作时,还要响应用户操作.这时候就需要用其他线程或者异步来搞.本来是改造公司的日志组件.因为多上了个国外大区的业务到来本系统来.这个系统其他地方都好就是日志,动不动就要死给我们看.有时候寻找 ...

  6. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  7. BPM任务管理解决方案分享

    一.方案概述任务是企业管理者很多意志的直接体现,对于非常规性事务较多的企业,经常存在各类公司下达的各种任务跟进难.监控难等问题,任务不是完成效果不理解,就是时间超期,甚至很多公司管理层下达的任务都不了 ...

  8. 用Java代码实现拦截区域网数据包

    起因: 吃饭的时间在想如果区域网内都是通过路由器上网,那如何实现拦截整个区域网的数据包,从而实现某种窥探欲. 思路:      正常是通过电脑网卡预先设置或分配的IP+网关对路由器进行通讯,比如访问百 ...

  9. 初识npm

    一.npm简介: npm全称为Node Package Manager,是一个基于Node.js的包管理器,也是整个Node.js社区最流行.支持的第三方模块最多的包管理器. npm的初衷:JavaS ...

  10. Asp.NET + SQLServer 部署注意事项

    1. 内存设置最大值(如果不设置, 会造成内存占用太大,带来性能问题) IIS 设置最大内存 sqlserver 设置最大内存