Guava学习笔记 1. 基本工具 [Basic utilities]

让使用 Java 语言变得更舒适

本文主要通过例子的方式简单介绍了一下基本工具的使用。
如果希望了解更多的细节,可以可以查看目录中的链接进行查看。
— By Syahfozy

1 使用和避免 null:null 是模棱两可的,会引起令人困惑的错误,有些时候它让人很不舒服。很多 Guava 工具类用快速失败拒绝 null 值,而不是盲目地接受

2 前置条件: 让方法中的条件检查更简单

3 常见 Object 方法: 简化 Object 方法实现,如 hashCode() 和 toString()

4 排序: Guava 强大的” 流畅风格比较器”

5 Throwables:简化了异常和错误的传播与检查

一、使用和避免null

很多 Guava 工具类用快速失败拒绝 null 值,而不是盲目地接受

大多数情况下,开发人员使用null表明的是某种缺失情形:可能是已经有一个默认值,或没有值,或找不到值。例如,Map.get返回null就表示找不到给定键对应的值

Guava用Optional表示可能为null的T类型引用。一个Optional实例可能包含非null的引用(我们称之为引用存在),也可能什么也不包括(称之为引用缺失)。它从不说包含的是null值,而是用存在或缺失来表示。但Optional从不会包含null值引用

1. 创建Optional实例

    /**
     * 创建Optional实例
     */
    public void makingAnOptional() {

        // 创建指定引用的Optional实例,若引用为null则快速失败
        Optional<Integer> possible = Optional.of(5);

        // 抛出 NullPointerException
        // Optional possible2 = Optional.of(null);


        // 创建引用缺失的Optional实例
        possible = Optional.absent();


        // 创建引用缺失的Optional实例
        possible = Optional.fromNullable(5);
        possible = Optional.fromNullable(null);
    }

2. 创建Optional实例

    /**
     * 用Optional实例查询引用
     */
    public void queryMethods() {
        Optional<Integer> possible = Optional.of(5);
        // 如果Optional包含非null的引用(引用存在),返回true
        possible.isPresent();

        // 返回Optional所包含的引用,若引用缺失,则抛出java.lang.IllegalStateException
        possible.get();

        // 返回Optional所包含的引用,若引用缺失,返回指定的值
        possible.or(3);

        // 返回Optional所包含的引用,若引用缺失,返回null
        possible.orNull();

        // 返回Optional所包含引用的单例不可变集
        // 如果引用存在,返回一个只有单一元素的集合,如果引用缺失,返回一个空集合
        possible.asSet();
    }

3. 其他处理null的便利方法

    /**
     * 其他处理null的便利方法
     */
    public void convenienceMethods() {

        // return 5
        MoreObjects.firstNonNull(5, 6);
        // return 6
        Optional.fromNullable(null).or(6);

        /**
         * 专门处理null或空字符串的方法
         */
        // return null
        emptyToNull("");

        // return true
        isNullOrEmpty("");
        isNullOrEmpty(null);

        // return ""
        nullToEmpty(null);
        // return "hello"
        nullToEmpty("hello");
    }

二、前置条件:让方法调用的前置条件判断更简单

Guava在Preconditions类中提供了若干前置条件判断的实用方法,每个方法都有三个变种:

  • 没有额外参数:抛出的异常中没有错误消息;
  • 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
  • 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符

1. 使用示例

// 没有额外参数:抛出的异常中没有错误消息
checkArgument(i <= 0);

// 有一个Object对象作为额外参数
checkArgument(i <= 0, "Argument Exception");

// 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象
checkArgument(i < j, "Expected i < j, but %s > %s", i, j);

2. 常用方法

/**
 * 检查boolean是否为true,用来检查传递给方法的参数
 * 检查失败时抛出 IllegalArgumentException
 */
checkArgument(Boolean.TRUE);

/**
 * 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull
 * 可以在构造函数中保持字段的单行赋值风格:this.field = checkNotNull(field)
 * 检查失败时抛出 NullPointerException
 */
checkNotNull(null);

/**
 * 用来检查对象的某些状态
 * 检查失败时抛出 IllegalStateException
 */
checkState(Boolean.FALSE);

/**
 * 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size
 * 检查失败时抛出 IndexOutOfBoundsException
 */
checkElementIndex(3,3);

/**
 * 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size
 * 检查失败时抛出 IndexOutOfBoundsException
 */
checkPositionIndex(3, 3);

/**
 * 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效
 * 检查失败时抛出 IndexOutOfBoundsException
 */
checkPositionIndexes(0, 3, 3);

三、常见Object方法

1. equals

/**
 * 使用Objects.equal帮助执行null敏感的equals判断,从而避免抛出NullPointerException
 * 注意:JDK7引入的Objects类提供了一样的方法Objects.equals
 */
public static void equalsMethod() {
    // returns true********
    Objects.equal("a", "a");
    // returns false
    Objects.equal(null, "a");
    // returns false
    Objects.equal("a", null);
    // returns true
    Objects.equal(null, null);

}

2. hashCode

/**
 * 对传入的字段序列计算出合理的、顺序敏感的散列值
 * 可以使用Objects.hashCode(field1, field2, …, fieldn)来代替手动计算散列值
 * 注意:JDK7引入的Objects类提供了一样的方法Objects.hash(Object...)
 */
public static void hashCodeMethod() {
    int hash = Objects.hashCode(2, "hello", null);
    System.out.println(hash);
}

3. toString

/**
 * 轻松编写有用的toString方法
 */
public void toStringHelperMethod() {

    // Returns "ClassName{x=1}"
    String s1 = MoreObjects.toStringHelper(this)
            .add("x", 1)
            .toString();
    System.out.println(s1);

    // Returns "MyObject{x=1}"
    String s2 = MoreObjects.toStringHelper("MyObject")
            .add("x", 1)
            .toString();
    System.out.println(s2);

}

4. compare/compareTo

class Person implements Comparable<Person> {
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 执行比较操作直至发现非零的结果,在那之后的比较输入将被忽略
     * @param that
     * @return
     */
    public int compareTo(Person that) {
        return ComparisonChain.start()
                .compare(this.age, that.age)
                .compare(this.name, that.name)
                .result();
    }
}
public void compare() {
    Person a = new Person("a", 10);
    Person b = new Person("a", 10);
    // Returns 1
    System.out.println(b.compareTo(a));
}

四、排序: Guava强大的”流畅风格比较器”

排序器[Ordering]是Guava流畅风格比较器[Comparator]的实现,它可以用来为构建复杂的比较器,以完成集合排序的功能

从实现上说,Ordering实例就是一个特殊的Comparator实例。Ordering把很多基于Comparator的静态方法(如Collections.max)包装为自己的实例方法(非静态方法),并且提供了链式调用方法,来定制和增强现有的比较器

1. 创建排序器

/**
 * 创建排序器
 * 常见的排序器可以由下面的静态方法创建
 */
public static void creationMethod(){

    // 对可排序类型做自然排序,如数字按大小,日期按先后排序
    Ordering<String> naturalOrdering = natural();
    // 按对象的字符串形式做字典排序
    Ordering<Object> usingToStringOrdering = usingToString();
    // 把给定的Comparator转化为排序器
    Ordering<String> fromOrdering = Ordering.from(new Comparator<String>() {
        public int compare(String o1, String o2) {
            return o1.hashCode() - o2.hashCode() ;
        }
    });
    // 直接继承Ordering
    Ordering<String> byLengthOrdering = new Ordering<String>() {
        public int compare(String left, String right) {
            return Ints.compare(left.length(), right.length());
        }
    };
}

2. 链式调用方法

通过链式调用,可以由给定的排序器衍生出其它排序器

/**
 * 链式调用方法
 * 通过链式调用,可以由给定的排序器衍生出其它排序器
 * 当阅读链式调用产生的排序器时,应该从后往前读,因为每次链式调用都是用后面的方法包装了前面的排序器
 * 用compound方法包装排序器时,不遵循从后往前读的原则
 */
public static void chainingMethod(){

    List<String> withNullList = Lists.newArrayList(list);
    withNullList.add(null);
    System.out.println("withNullList:"+ withNullList);
    
    List<List> listList = Lists.newArrayList();
    listList.add(Lists.newArrayList("perter", "jerry"));
    listList.add(Lists.newArrayList("perter"));
    listList.add(Lists.newArrayList("perter", "jerry", null));
    System.out.println("listList:"+ withNullList);
    
    // 对可排序类型做自然排序,如数字按大小,日期按先后排序
    Ordering<String> naturalOrdering = natural();
    // 获取语义相反的排序器
    Ordering<String> reverseOrdering = natural().reverse();
    // 使用当前排序器,但额外把null值排到最前面
    Ordering<String> nullsFirst = natural().nullsFirst();
    // 使用当前排序器,但额外把null值排到最后面
    Ordering<String> nullsLast = natural().nullsLast();
    // 合成另一个比较器,以处理当前排序器中的相等情况
    Ordering<People> secondaryOrdering = new PeopleAgeOrder().compound(new PeopleNameLengthOrder());
    // 返回该类型的可迭代对象Iterable<T>的排序器
    Ordering lexicographicalOrdering = naturalOrdering.lexicographical();
    // 对集合中元素调用Function,再按返回值用当前排序器排序
    Ordering<String> resultOfOrdering = natural().nullsFirst().onResultOf(new Function<String, Integer>() {
        public Integer apply(String input) {
            return input == null ? null : input.length();
        }
    });
}

3. 运用排序器

/**
 * 运用排序器
 * Guava的排序器实现有若干操纵集合或元素值的方法
 */
public static void applicationMethod() {

    // 获取可迭代对象中最大的k个元素
    System.out.println("greatestOfOrdering:"+ natural().greatestOf(list, 3));
    System.out.println("leastOfOrdering:"+ natural().leastOf(list, 3));

    // 判断可迭代对象是否已按排序器排序
    // 允许有排序值相等的元素
    System.out.println("isOrdered:"+ natural().isOrdered(natural().sortedCopy(list)));
    // 判断可迭代对象是否已严格按排序器排序
    // 不允许有排序值相等的元素
    System.out.println("isStrictlyOrdered:"+ natural().isStrictlyOrdered(natural().sortedCopy(list)));

    // 以列表形式返回指定元素的已排序副本
    System.out.println("isOrdered:"+ natural().sortedCopy(list));
    // 返回包含按此排序排序的元素的不可变列表
    natural().immutableSortedCopy(list);

    // 返回两个参数中最小的那个。如果相等,则返回第一个参数
    System.out.println("min:" + natural().min("abc", "ab"));
    // 返回两个参数中最大的那个。如果相等,则返回第一个参数
    System.out.println("max:" + natural().max("abc", "ab"));

    // 返回多个参数中最小的那个。如果有超过一个参数都最小,则返回第一个最小的参数
    System.out.println("min:" + natural().min("ab", "cd", "abc"));
    // 返回多个参数中最大的那个。如果有超过一个参数都最大,则返回第一个最大的参数
    System.out.println("max:" + natural().max("ab", "cde", "abc"));

    // 返回迭代器中最小的元素。如果可迭代对象中没有元素,则抛出NoSuchElementException
    System.out.println("min:" + natural().min(list));
    // 返回迭代器中最大的元素。如果可迭代对象中没有元素,则抛出NoSuchElementException
    System.out.println("max:" + natural().max(list));

}

五、Throwables:简化异常和错误的传播与检查

1. 异常传播方法

Guava中的异常传播方法简要列举如下:

// 类型为 X 时才抛出
Throwables.throwIfInstanceOf(t, SQLException.class);

// 类型为Error或RuntimeException时抛出
Throwables.throwIfUnchecked(t);

2. 异常原因链

Guava提供了如下三个有用的方法,让研究异常的原因链变得稍微简便了,这三个方法的签名是不言自明的:

// 获取异常原因链
Throwable throwable = Throwables.getRootCause(t);
List<Throwable> throwables = Throwables.getCausalChain(t);
String str = Throwables.getStackTraceAsString(t);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值