Google Guava

本文深入解析了Google Guava库与Java8中的Optional类,涵盖了Optional的背景、使用场景、方法详解及源码分析,同时对比了Guava与Java8中Optional的不同之处,帮助开发者有效避免空指针异常,提升代码质量。


一. Guava概述

  1. Guava是 Google公司基于java1.6的类库集合的扩展项目,其中包含谷歌很多项目使用的核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。(官方Guava API)。
  2. 源码包概述
    com.google.common.annotations:普通注解类型。
    com.google.common.base:基本工具类库和接口。
    com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。
    com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类,这里你会发现很多好玩的集合。
    com.google.common.eventbus:发布订阅风格的事件总线。
    com.google.common.io:I/O工具包。
    com.google.common.net:网络工具包。
    com.google.common.primitives:八种原始类型和无符号类型的静态工具包。
    com.google.common.util.concurrent:多线程工具包。
  3. Guava maven依赖
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>25.0-jre</version>
    </dependency>
    

二. Strings类

  1. 所在包:com.google.common.base包。
  2. 常用方法
    public static String nullToEmpty(@Nullable String string):如果string为null,则返回"";否则,返回str本身
    public static String emptyToNull(@Nullable String string):如果string为"",则返回null;否则,返回string本身
    public static boolean isNullOrEmpty(@Nullable String string):如果string为null或"",则返回true;否则,返回false
  3. 常用方法源码
    package com.google.common.base;
    
    public final class Strings {
    
      public static String nullToEmpty(@Nullable String string) {
        return (string == null) ? "" : string;
      }
      
     
      @Nullable
      public static String emptyToNull(@Nullable String string) {
        return isNullOrEmpty(string) ? null : string;
      }
      
      public static boolean isNullOrEmpty(@Nullable String string) {
        return string == null || string.length() == 0; // string.isEmpty() in Java 6
      }
    }
    
  4. 使用示例
    public class StringsTest {
        public static void main(String[] args) {
            String str1 = "";
            String str2 = null;
            String str3 = "娃哈哈";
    
            // 1. Strings.isNullOrEmpty(String str)
            boolean flag1 = Strings.isNullOrEmpty(str1); //true
            boolean flag2 = Strings.isNullOrEmpty(str2); //true
            boolean flag3 = Strings.isNullOrEmpty(str3); //false
    
            System.out.println("|"+str1+"|"); // ||
            System.out.println("|"+str2+"|"); // |null|
            System.out.println("|"+str3+"|"); // |娃哈哈|
    
     		// 2. Strings.nullToEmpty(String str)
            String tempStr1=  Strings.nullToEmpty(str1);
            String tempStr2=  Strings.nullToEmpty(str2);
            String tempStr3=  Strings.nullToEmpty(str3);
    
            System.out.println("|"+tempStr1+"|"); // ||
            System.out.println("|"+tempStr2+"|"); // ||
            System.out.println("|"+tempStr3+"|"); // |娃哈哈|
    
            // 3. Strings.emptyToNull(String str)
            String tempStr4=  Strings.emptyToNull(str1);
            String tempStr5=  Strings.emptyToNull(str2);
            String tempStr6=  Strings.emptyToNull(str3);
    
            System.out.println("|"+tempStr4+"|"); // |null|
            System.out.println("|"+tempStr5+"|"); // |null|
            System.out.println("|"+tempStr6+"|"); // |娃哈哈|
    
        }
    }
    

三. Preconditions类

  1. 所在包:com.google.common.base
  2. 概述:用来做参数校验
  3. 常用方法
    public static <T> T checkNotNull(T reference, @NullableDecl Object errorMessage):判断参数是否为null。如果为null,则抛出NullPointerException空指针异常。
    public static void checkArgument(boolean expression, @NullableDecl Object errorMessage):判断参数是否符合某种条件。当不符合条件时,则抛出illegalArgumentException异常。
    public static int checkElementIndex(int index, int size, @NullableDecl String desc):判断index是否在[0,size)范围内。如果在0<=index<size,则通过;否则,抛出IndexOutOfBoundsException异常。
  4. 使用示例
    public class PreconditionsTest {
    
        public static void main(String[] args) throws Exception{
        	// 1. 校验通过示例
    	    Person person = new Person("xixi",24,"西西吃烤肉去了~");
            check(person); // 输出结果:参数校验通过!
       
    		// 2. 校验未通过示例
    		Person person2 = new Person(null,24,"西西吃烤肉去了~");
         	check(person); // 输出结果:见下
        }
    
        public static void check(Person person){
            Preconditions.checkNotNull(person.getName(), "Name may not be Null!");
            Preconditions.checkArgument(person.getAge() >= 18 && person.getAge() < 99, "age must in range (18,99)");
            Preconditions.checkArgument(person.getDecs() !=null, "desc may not be Null ");
            Preconditions.checkElementIndex(0,7,"0<=index<size");
            System.out.println("参数校验通过!");
        }
    }
    
    class Person{
        String name;
        int age;
        String decs;
        
        //getter and setter
    }
    
  • 校验未通过的输出结果
objc[49493]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/bin/java (0x1020374c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x1020b74e0). One of the two will be used. Which one is undefined.
java.lang.NullPointerException: Name may not be Null!
	at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:900)
	at guava.PreconditionsTest.check(PreconditionsTest.java:21)
	at guava.PreconditionsTest.main(PreconditionsTest.java:11)
Name may not be Null!

四. Optional类

1. 背景与概述

  1. Optional类出现的背景:Java应用程序最常见的空指针异常
  2. 解决空指针异常的通用解决方法
    if(name != null){
         name.defaultName();
    }
    
  3. 概述
    1. 为了解决空指针异常,Google公司最先在Guava项目中引入Optional类,通过检查空值的方式来防止代码污染。
    2. 受Google Guava的启发,Optional类已成为Java 8类库的一部分。Optional实际上是个容器:它可以保存类型为T的值,或者仅仅保存null。
    3. Optional类提供了很多有用的方法,这样就可以不显式进行空值检测。

2. Guava Optional类

2.1 概述
  • Guava的Optional实例要么包含一个非空对象,要么什么都不包含,但不会出现包含一个空引用的情况。因此一个Optional对象定义了两种类型来分别表示它们: Present和Absent。
2.2 常用方法
  1. 创建Optional实例的方法
    • public static <T> Optional<T> of(T reference):创建一个包含非空对象的Optional。如果reference为null,则抛出NullPointerException。
    • public static <T> Optional<T> absent():创建一个不包含对象的Optional实例(Absent)。
    • public static <T> Optional<T> fromNullable(@Nullable T nullableReference):如果nullableReference非空,则创建一个包含这个非空对象的Optional实例;否则创建一个不包含对象的Optional实例(Absent)。
  2. 获得被包装对象的方法
    • public abstract T get():返回被包含的对象。如果实例是Absent,则抛出illegalStateException。
    • public abstract T or(T defaultValue):返回被包含的对象。如果实例是Absent,返回defaultValue。
    • public abstract T orNull():返回被包含的对象。如果实例是Absent,返回Null。
2.3 源码参考
  1. Optional类
public abstract class Optional<T> implements Serializable {
	// 1. 创建Optional实例
	public static <T> Optional<T> of(T reference) {
    	return new Present<T>(checkNotNull(reference));
  	}
  	public static <T> Optional<T> absent() {
    	return Absent.withType();
  	}
  	public static <T> Optional<T> fromNullable(@NullableDecl T nullableReference) {
    	return (nullableReference == null) ? Optional.<T>absent() : new Present<T>(nullableReference);
  	}
  	
  	// 2. 是否为Present对象
  	public abstract boolean isPresent();
  	
  	// 3. 获得对象
  	public abstract T get();
  	public abstract T or(T defaultValue);
  	public abstract T orNull();
}
  1. Present类
final class Present<T> extends Optional<T> {
	private final T reference;
	
	@Override
  	public boolean isPresent() {
    	return true;
  	}
	@Override
	public T get() {
	   return reference;
	}

	@Override
	public T or(T defaultValue) {
		checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
		return reference;
	}
	
	@Override
	public T orNull() {
		return reference;
	}
}
  1. Absent类
final class Absent<T> extends Optional<T> {
	static final Absent<Object> INSTANCE = new Absent<Object>();
  
	static <T> Optional<T> withType() {
		return (Optional<T>) INSTANCE;
	}
	
	@Override
	public boolean isPresent() {
		return false;
	}
	
	@Override
	public T get() {
		throw new IllegalStateException("Optional.get() cannot be called on an absent value");
	}
	
	@Override
	public T or(T defaultValue) {
		return checkNotNull(defaultValue, "use Optional.orNull() instead of Optional.or(null)");
	}
	
	public T orNull() {
		return null;
	}
}
2.4 测试
// 1. Absent对象
Optional<Integer> optionalAbsent = Optional.absent();
// Integer b = optionalAbsent.get(); // 抛出IllegalStateException
Integer a = optionalAbsent.or(2); // 2
Integer c = optionalAbsent.orNull(); // null

// 2. Present对象
Optional<Integer> optionalPresent = Optional.of(3);
Integer aa = optionalPresent.get(); //3
Integer bb = optionalPresent.or(3); //3
Integer cc = optionalPresent.orNull(); //3

3. Java 8 中Optional类

3.1 部分源码
public final class Optional<T> {
	private static final Optional<?> EMPTY = new Optional<>();
	private final T value;
	private Optional() {
        this.value = null;
    }
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    public static<T> Optional<T> empty() {
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
    public boolean isPresent() {
        return value != null;
    }
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
    public T orElse(T other) {
       return value != null ? value : other;
   }
   public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
}
3.2 创建Optional对象的方法
  1. 方法概述
    • public static <T> Optional<T> of(T value):创建一个包含非空对象的Optional。如果value为null,则抛出NullPointerException。
    • public static <T> Optional<T> ofNullable(T value):创建一个Optional对象。如果value非空,则创建一个包含这个非空对象的Optional实例;否则,创建一个不包含对象的Optional实例。
    • public static<T> Optional<T> empty():创建一个不包含对象的Optional实例。
  2. 使用
    // 1. Optional.of()
    Optional<Integer> optional1 = Optional.of(1);
    // Optional<Integer> optional2 = Optional.of(null); // NullPointerException
    
    // 2. Optional.ofNullable()
    Optional<Integer> optional3 = Optional.ofNullable(2);
    Optional<Integer> optional4 = Optional.ofNullable(null);
    Optional<Integer> optional5 = Optional.ofNullable(null);
    
    // 3. Optional.empty()
    Optional<Integer> optional6 = Optional.empty();
    
    System.out.println(optional4==optional5); //true
    System.out.println(optional5==optional6); // true
    
3.3 判断值是否存在
  1. 概述
    • public boolean isPresent():判断值是否存在。
  2. 使用
    Optional<Integer> optional1 = Optional.of(1);
    Optional<Integer> optional2 = Optional.ofNullable(null);
    
    boolean optional1FLag = optional1.isPresent(); // true
    boolean optional2Flag = optional2.isPresent(); // false
    
3.4 获得值
  1. 概述
    • public T get():如果optional对象的value值不为空,则返回该value;否则,抛出NoSuchElementException异常。
    • public T orElse(T other):如果optional对象保存的value值不为null,则返回value值,否则返回other值。
  2. 使用
    Optional<Integer> optional1 = Optional.of(1);
    Optional<Integer> optional2 = Optional.ofNullable(null);
    
    // 1. get()
    System.out.println(optional1.get()); // 1
    System.out.println(optional2.get()); // 抛出NoSuchElementException
            
    // 2. orElse(T other)
    System.out.println(optional1.orElse(1000)); // 1
    System.out.println(optional2.orElse(1000)); // 1000
    
3.5 ifPresent(Consumer consumer)
  1. 概述
    • public void ifPresent(Consumer<? super T> consumer):如果option对象保存的value值不为null,则调用consumer对象,否则不调用。
    • Consumer类
      @FunctionalInterface
      public interface Consumer<T> {
      	void accept(T t);
      	
      	default Consumer<T> andThen(Consumer<? super T> after) {
              Objects.requireNonNull(after);
              return (T t) -> { accept(t); after.accept(t); };
          }
      }
      
  2. 使用
    Optional<Integer> optional1 = Optional.of(1);
    Optional<Integer> optional2 = Optional.ofNullable(null);
    
     // 如果value不是null,则调用Consumer
     optional1.ifPresent(new Consumer<Integer>() {
         @Override
         public void accept(Integer t) {
             System.out.println("value is " + t); // value is 1
         }
     });
    
     // 如果value为null,则不调用Consumer
     optional2.ifPresent(new Consumer<Integer>() {
         @Override
         public void accept(Integer t) {
             System.out.println("value is " + t); // optional2的ifPresent()方法不会被调用
         }
     });
    
3.6 filter(Predicate predicate)
  1. 概述
    • public Optional<T> filter(Predicate<? super T> predicate):如果optional实例的value值存在,并且value值满足给定的predicate.test()方法,则返回该Optional实例;否则,返回一个empty Optional实例。如果predicate为null,则抛出NullPointerException。
    • Predicate类
      @FunctionalInterface
      public interface Predicate<T> {
      	boolean test(T t);
      	// ...
      }
      
  2. 使用
    Optional<Integer> optional1 = Optional.of(1);
    Optional<Integer> optional2 = Optional.ofNullable(null);
    
    Optional<Integer> filter1 = optional1.filter((a) -> a == null);
    System.out.println(filter1.isPresent()); // false
    
    Optional<Integer> filter2 = optional1.filter((a) -> a == 1);
    System.out.println(filter2.isPresent()); // true
    
    Optional<Integer> filter3 = optional2.filter((a) -> a == null);
    System.out.println(filter3.isPresent()); // false
    
3.7 map(Function mapper)
  1. 概述
    • public<U> Optional<U> map(Function<? super T, ? extends U> mapper):如果value值不为null,则对value值进行函数运算,并返回新的Optional(可以是任何类型),否则返回一个empty的optional实例。如果function对象为null,抛出NullPointerException异常。
    • Function类
      @FunctionalInterface
      public interface Function<T, R> {
      	R apply(T t);
      	// ...
      }
      
  2. 使用
    Optional<Integer> optional1 = Optional.of(1);
    Optional<Integer> optional2 = Optional.ofNullable(null);
    
    Optional<String> mapOptional1 = optional1.map((a) -> "key" + a);
    Optional<String> mapOptional2 = optional2.map((a) -> "key" + a);
    
    System.out.println(mapOptional1.get()); // key1
    System.out.println(mapOptional2.isPresent());// false
    

五. Guava 集合

1. 集合创建和初始化

/**
* 集合创建
*/
List<String> list = Lists.newArrayList();
Map<String,Object> map = Maps.newHashMap();

/**
* 集合创建并初始化
*/
List<String> list2 = Lists.newArrayList("one","two","three");
Set<String> set2 = Sets.newHashSet("1","2","3");

2. 创建不可变集合

  1. 之前用法:Collections.unmodifiableList(),并不是真正的不可变集合

  2. Collections.unmodifiableList()的使用

    List<String> list = new ArrayList<String>();
    list.add("1");
    list.add("2");
    list.add("3");
    
    final List<String> imList = Collections.unmodifiableList(list);
    System.out.println(imList); // [1, 2, 3]
    // imList.add("1"); //抛出异常
    

    一切看起来很不错。但如果有用户修改了list,会发生什么情况?

    List<String> list = new ArrayList<String>();
    list.add("1");
    list.add("2");
    list.add("3");
    
    final List<String> imList = Collections.unmodifiableList(list);
    System.out.println(imList); // [1, 2, 3]
    
    list.add("1");
    System.out.println(imList); //[1, 2, 3, 1]
    

    可见,我们的不可变集合imList此时增加了一个元素,因此Collections.unmodifiableList(…)实现的不是真正的不可变集合,当原始集合被修改后,不可变集合里面的元素也是跟着发生变化。

  3. Guava提供的Immutable:真正的不可变集合

    /**
     * 常量List
     */
    ImmutableList<String> imList = ImmutableList.of("a","b","c");
    //imList.add("2"); //抛出异常
    for(String s:imList){
       System.out.println(s);
    }
    
    /**
     * 常量Map
     */
    ImmutableMap<String,String> immap
           = new ImmutableMap.Builder<String,String>()
                       .put("a","1")
                       .put("b","2")
                       .put("c", "3")
                       .build();
    for(Map.Entry<String,String> e:immap.entrySet()){
          System.out.println(e.getKey()+"="+e.getValue());
     }
    
    /**
     * 常量Set
     */
    ImmutableSet<String> imset=ImmutableSet.of("a","b","c");
    for(String s:imset){
       System.out.println(s);
    }
    

参考资料

JDK8新特性:使用Optional避免null导致的NullPointerException
Guava Optional 和 Java 8 optional
Java类库Google Guava扩展项目学习笔记
Immutable不可变集合
理解不可变集合 | Guava Immutable与JDK unmodifiableList
Guava教程

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值