Guava工具类学习

一、介绍

1、常用点:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等
2、开源的Java库,这个库是为了方便编码,并减少编码错误。

二、Optional类

1、定义

官方解释:用于包含非空对象的不可变对象,Optional对象不存在值表示null。
个人解释:换言之就是把变量转成Optional对象,其中null都转成Optional.absent()(就是一个空的Optional对象),然后就可以对Optional对象进行操作。好处就是发现null可选择抛出异常。

2、java8自带Optional

所以建议直接用java8自带的就好了,用法一样,只是方法名字稍微不一样

3、使用

关键方法(解释看代码):fromNullable、of、get、or、isPresent

@Test
public void OptionalTest() {
	handleParam(null,1); //后面两个参数自己随意写
}

//处理参数举例子
void handleParam(String a,Integer b){
	//对于处理string参数
	Optional<String> aOpt = Optional.fromNullable(a); //允许参数空。如果非空返回一个包含引用Optional实例,否则返回Optional.absent()。
    System.out.println(aOpt.isPresent());//输出aOpt是否为空
	a=aOpt.or("defaultValue");//如果为空,就给一个默认值defaultValue
	System.out.println(a);

	//同理对于处理int参数
	Optional<Integer> bOpt = Optional.of(b);//不允许参数空,不然会抛出异常
	b=bOpt.get();//get的时候不允许变量为空
	System.out.println(b);
}

三、Preconditions类

1、定义

官方解释:检查方法的参数是否符合业务
个人感觉:我不喜欢这个,我觉得没什么用,用到的几率太小,要一直捕获exception

2、使用

关键方法(解释看代码):checkArgument、checkState;checkPositionIndex、checkElementIndex;checkNotNull

	@Test
	public void PreconditionsTest() {
		try {
			System.out.println(sqrt(-3.0));  //计算开方
		}catch(Exception e){
			System.out.println(e.getMessage());
		}
		try {
			System.out.println(sum(null,3)); //计算和
		}catch(NullPointerException e){
			System.out.println(e.getMessage());
		}
		try {
			System.out.println(getValue(-1,6));//判断下标是否有效
		}catch(IndexOutOfBoundsException e){
			System.out.println(e.getMessage());
		}
	}

	public double sqrt(double input) {
		Preconditions.checkArgument(input > 0.0, "非法参数: 参数为%s", input);//和checkState差不了多少
		return Math.sqrt(input);
	}

	public int sum(Integer a, Integer b){
		Preconditions.checkNotNull(a, "非法参数: 参数为空");
		Preconditions.checkNotNull(b, "非法参数: 参数为空");
		return a+b;
	}

	public int getValue(int index, int size){
		 Preconditions.checkPositionIndex(index, size, "无效的下标");//和checkElementIndex差不了多少
		return index;
	}

四、Ordering类

1、定义

官方解释:Ordering(排序)可以被看作是一个丰富的比较具有增强功能的链接,多个实用方法,多类型排序功能等
个人解释:反正就是列表的排序,倒序,取最大最小,取从最大到最小的k个最大的元素,取从小到最大的k个最小的元素,亮点是可以兼容null

2、使用

关键方法(解释看代码):greatestOf、leastOf;min、max;sortedCopy、isOrdered、reverse;nullsFirst、nullsLast

@Test
public void OrderingTest() {
	List<Integer> myList = new ArrayList<Integer>();
	myList.add(new Integer(5));
	myList.add(new Integer(2));
	myList.add(new Integer(15));
	myList.add(new Integer(51));
	myList.add(new Integer(53));
	myList.add(new Integer(35));
	myList.add(new Integer(45));
	myList.add(new Integer(32));
	myList.add(new Integer(43));
	myList.add(new Integer(16));

	Ordering ordering = Ordering.natural();

	//从最大到最小的k个最大的元素
	List list1 = ordering.greatestOf(myList, 3);
	System.out.println("从最大到最小的k个最大的元素list1:"+list1);//输出[53, 51, 45]
	//从小到最大的k个最小的元素
	List list2 = ordering.leastOf(myList, 3);
	System.out.println("从小到最大的k个最小的元素list2:"+list2);//输出[2, 5, 15]
	//最小元素
	int min = (int) ordering.min(myList);
	System.out.println("最小元素:"+min);//输出2
	//最大元素
	int max = (int) ordering.max(myList);
	System.out.println("最大元素:"+max);//输出53


	//排序后复制,原list不变,从小到大排序
	List list3 = ordering.sortedCopy(myList);
	System.out.println("从小到大排序后复制给list3:"+list3);//输出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
	System.out.println("原mylist:"+myList);//输出[5, 2, 15, 51, 53, 35, 45, 32, 43, 16]
	//排序也可以直接用Collections.sort,从小到大排序,正常情况下此方法禁止list含null
	Collections.sort(myList);
	System.out.println("从小到大排序好原mylist:"+myList);//输出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
	//查看是否已经从小到大好了序,该方法禁止list含null,如果是从大到小则返回false
	boolean isOrdered = ordering.isOrdered(myList);
	System.out.println("查看是否已经排好了序:"+isOrdered);//输出true
	//换成从大到小排序或者是翻转
	Collections.sort(myList,ordering.reverse());
	System.out.println("从大到小排序好原mylist:"+myList);//输出53, 51, 45, 43, 35, 32, 16, 15, 5, 2]


	//ordering允许list含有null
	myList.add(null);
	//对待null小于所有其他值
	Collections.sort(myList,ordering.nullsFirst());
	System.out.println("添加null以后,对待null小于所有其他值,myList为:"+myList);//输出[null, 2, 5, 15, 16, 32, 35, 43, 45, 51, 53]
	//对待null大于所有其他值
	Collections.sort(myList,ordering.nullsLast());
	System.out.println("添加null以后,对待null大于所有其他值,myList为:"+myList);//输出[2, 5, 15, 16, 32, 35, 43, 45, 51, 53, null]

}

五、Range类

1、定义

官方解释:Range 表示一个间隔或一个序列。它被用于获取一组数字/串在一个特定范围之内。Range定义了连续跨度的范围边界,这个连续跨度是一个可以比较的类型(Comparable type)。比如1到100之间的整型数据。
个人解释:可以生产区间,就是一段连续的整型数据,可以判断是否存在或者获取两个区间的交集和并集,可以判断是否存在或者获取一个区间的最低端点和上限端点,可以查询一个区间是包含一个或者多个元素。

2、生产区间的方法

概念 表示范围 guava对应功能方法
(a..b) ` {x a < x < b} `
[a..b] ` {x a <= x <= b} `
[a..b) ` {x a <= x < b} `
(a..b] ` {x a < x <= b}`
(a..+∞) ` {x x > a}`
[a..+∞) ` {x x >= a}`
(-∞..b) ` {x x < b}
(-∞..b] ` {x x <= b}`
(-∞..+∞) all values all()

3、使用

关键方法(解释看代码):lowerEndpoint,upperEndpoint,hasUpperBound,hasLowerBound;encloses,isConnected,intersection

   @Test
	public void RangeTest(){
		System.out.println("-------------------基本获取---------------------");
		//创建一个范围 [a,b]
		Range<Integer> range1 = Range.closed(0, 9);
		System.out.println("生成range1 [0,9]: "+ range1.toString()); //输出[0‥9]
		//查看Range是否存在某个或某些值
		System.out.println("range1是否存在5: " + range1.contains(5));//输出true
		System.out.println("range1是否存在(1,2,3): " + range1.containsAll(Ints.asList(1, 2, 3)));//输出true

		//查看Range的最低端点和上限端点。
		System.out.println("range1的最低端点: " + range1.lowerEndpoint());//输出0
		System.out.println("range1是否有上端点: " + range1.hasUpperBound());//输出true
		System.out.println("range1的上限端点: " + range1.upperEndpoint());//输出9

		System.out.println("------------------闭区间和开区间----------------------");

		//创建一个范围 (a,b)
		Range<Integer> range2 = Range.open(0, 9);
		System.out.println("生成range2 (0,9) :"+range2.toString());

		//创建一个范围 (a,b]
		Range<Integer> range3 = Range.openClosed(0, 9);
		System.out.println("生成range3 (0,9] : "+range3.toString());

		//创建一个范围 [a,b)
		Range<Integer> range4 = Range.closedOpen(0, 9);
		System.out.println("生成range4 [0,9) : "+range4.toString());

		//返回一个包含所有值严格大于端点的范围内 (a,∞)
		Range<Integer> range5 = Range.greaterThan(9);
		System.out.println("生成range5 (9,∞) : "+range5.toString());
		System.out.println("range5是否有上端点: " + range5.hasUpperBound());

		System.out.println("------------------交集和并集----------------------");

		Range<Integer> range6 = Range.closed(3, 5);

		//是否包含子集
		System.out.println("range1 [0,9] 是否包含 range6 [3,5]:" + range1.encloses(range6));

		Range<Integer> range7 = Range.closed(9, 20);

		//是否有交集
		System.out.println("range1 [0,9] 和 range7 [9,20]是否有交集:" + range1.isConnected(range7));

		Range<Integer> range8 = Range.closed(5, 15);

		//返回由两者范围和connectedRange封闭,如果这样的范围存在的最大范围。如果不相连时,直接抛出异常
		System.out.println("range1 [0,9]和 range8 [5,15]的交集:"+range1.intersection(range8).toString());

		//返回最小的范围包围两者这个范围和other等。
		System.out.println("range1 [0,9]和 range8 [5,15]的并集:"+range1.span(range8).toString());
       
       System.out.println("-------------------拓展---------------------");
		//输出有限range
		ContiguousSet<Integer> set = ContiguousSet.create(range8, DiscreteDomain.integers());
		for(int grade : set) {
			System.out.print(grade +" ");
		}

	}


六、Multiset接口

1、定义

Multiset接口扩展设置有重复的元素,并提供了各种实用的方法来处理这样的元素在集合中出现。

2、使用

关键方法(解释看代码):elementSet、iterator;count、contains、containsAll、size;add、remove

  @Test
	public void MultisetTest(){
		//创建一个multiset
		Multiset<String> multiset = HashMultiset.create();
		multiset.add("a");multiset.add("b");multiset.add("c");
		multiset.add("d");multiset.add("a");multiset.add("b");
		multiset.add("c");multiset.add("b");multiset.add("b");

		System.out.print("把multiset转成无重复set:");
		Set<String> set = multiset.elementSet();
		set.forEach(e-> System.out.print(e+" "));//输出a b c d

		System.out.print("\n把multiset转成可重复且有序的Iterator:");
        Iterator<String> iterator  = multiset.iterator();
        iterator.forEachRemaining(e-> System.out.print(e+" "));//输出a a b b b b c c d

        System.out.println("\n含有几个'b' : "+multiset.count("b"));//输出4
        System.out.println("是否包含e' : "+multiset.contains("e"));//输出false
        System.out.println("总size : "+multiset.size());//输出9

        //移除i个某元素
        System.out.println("移除1一个元素a");
        multiset.remove("a",1);
        //增加i个某元素
        System.out.println("增加2个元素c");
        multiset.add("c",2);

		//显示集合的不同元素及其出现次数
		System.out.print("遍历打印出multiset的元素和个数:");
        multiset.entrySet().forEach(entry->System.out.print("元素"+entry.getElement() +"的个数为 " + entry.getCount()+";"));//元素a的个数为 1;元素b的个数为 4;元素c的个数为 4;元素d的个数为 1;

    }

七、Bimap接口

1、定义

BiMap确保没有重复的值,且可以从value获取key

2、使用

关键方法(解释看代码):put、forcePut;inverse

   @Test
    public void BimapTest(){
        BiMap<Integer, String> empIDNameMap = HashBiMap.create();

        empIDNameMap.put(101, "Mahesh");
        empIDNameMap.put(102, "Sohan");
        empIDNameMap.put(103, "Ramesh");
        //亮点:如果key已经存在,强制覆盖
        empIDNameMap.forcePut(101, "Mahesh1");
        //亮点:根据值找到key 。inverse():生成value到key的逆视图
        System.out.println(empIDNameMap.inverse().get("Mahesh"));//输出null
        System.out.println(empIDNameMap.inverse().get("Mahesh1"));//输出101

        //把所有value转成set集合
        Set<String> values = empIDNameMap.values();
        values.forEach(e-> System.out.print(e+" "));//输出Ramesh Mahesh1 Sohan
    }

八、Bimap接口

1、定义

Table代表一个特殊的映射,其中两个键可以在组合的方式被指定为单个值。它类似于创建映射的映射。
简单点说就是有rowKey,有columnKey,匹配对应value

2、使用

关键方法(解释看代码):put、row、rowKeySet、column

 @Test
    public void TableTest(){

        //创建一个表
        Table<String, String, String> employeeTable = HashBasedTable.create();
        employeeTable.put("IBM", "101","Mahesh");
        employeeTable.put("IBM", "102","Ramesh");
        employeeTable.put("IBM", "103","Suresh");

        employeeTable.put("Microsoft", "101","Sohan");
        employeeTable.put("Microsoft", "102","Mohan");
        employeeTable.put("Microsoft", "103","Rohan");

        employeeTable.put("TCS", "121","Ram");
        employeeTable.put("TCS", "122","Shyam");
        employeeTable.put("TCS", "123","Sunil");

        //获取某一行的所有列
        Map<String,String> ibmEmployees =  employeeTable.row("IBM");
        System.out.println("rowKey为IBM的这一行的所有列为");
        ibmEmployees.entrySet().forEach(entry ->System.out.println("列字段columnKey: " + entry.getKey() + ", 值value: " + entry.getValue()));//输出列字段columnKey: 103, 值value: Suresh \n 列字段columnKey: 101, 值value: Mahesh \n 列字段columnKey: 102, 值value: Ramesh


        //获取所有行的rowkey,自动按照字母顺序
        Set<String> employers = employeeTable.rowKeySet();
        System.out.print("所有的rowKey为: ");
        employers.forEach(employer-> System.out.print(employer + "、"));//输出IBM、TCS、Microsoft

        //获取某一列的所有行和值
        System.out.println("\ncolumnKey为102的所有行和值为");
        Map<String,String> EmployerMap =  employeeTable.column("102");
        EmployerMap.entrySet().forEach( entry->System.out.println("行字段rowKey: " + entry.getKey() + ", 值value: " + entry.getValue()));//输出行字段rowKey: IBM, 值value: Ramesh \n 行字段rowKey: Microsoft, 值value: Mohan
    }

九、LoadingCache

1、定义

在缓存中自动加载值,它提供了许多实用的方法,在有缓存需求时非常有用。
优点:

  • 线程安全的缓存,与ConcurrentMap相似,但前者增加了更多的元素失效策略,后者只能显示的移除元素。
  • 提供了三种基本的缓存回收方式:基于容量回收、定时回收和基于引用回收。定时回收有两种:按照写入时间,最早写入的最先回收;按照访问时间,最早访问的最早回收。
  • 监控缓存加载/命中情况
  • 集成了多部操作,调用get方式,可以在未命中缓存的时候,从其他地方获取数据源(DB,redis),并加载到缓存中。

缺点:

  • Guava Cache的超时机制不是精确的。
  • 不能持久化本地缓存

2、使用

关键方法(驾驶看代码):getIfPresent、get、put、putAll、invalidate、
invalidateAll、refresh、size、stats、asMap、



public class GuavaTester {
    public static void main(String args[]) {
        //定义一个LoadingCache
        LoadingCache employeeCache = CacheBuilder.newBuilder()
                .concurrencyLevel(8)//设置并发级别为8,并发级别是指可以同时写缓存的线程数
                .maximumSize(100) // 设置缓存最大容量为100,超过100之后就会按照LRU最近虽少使用算法来移除缓存项
                .expireAfterWrite(10, TimeUnit.MINUTES)//设置写缓存后10分钟后过期
                .expireAfterAccess(30, TimeUnit.MINUTES) // 设置缓存在访问30分钟后过期
                .initialCapacity(10) //设置缓存容器的初始容量为10
                .recordStats() //设置要统计缓存的命中率,开启统计信息开关,
                .removalListener(notification -> System.out.println("key为"+notification.getKey() + "的缓存被移除了, 因为" + notification.getCause()))//设置缓存的移除通知
                .build(new CacheLoader() { //build方法中可以指定CacheLoader,,用于从数据源加载数据,在缓存不存在时可自定义策略,比如从数据库获取数据
                    @Override
                    public Object load(Object key) throws Exception {
                        //从数据库拿数据
                        return getFromDatabase(key.toString()); //自定义
                    }

                });


        try {
            //第一次调用时,缓存没有命中,会从数据库拿数据,如果数据库没有就直接抛异常
            System.out.println("第一次调用:");
            System.out.println(employeeCache.get("100"));//输出Employee(name=Mahesh, dept=Finance, emplD=100)
            System.out.println(employeeCache.get("103"));//输出Employee(name=Rohan, dept=IT, emplD=103)
            System.out.println(employeeCache.get("110"));//输出EmployeeEmployee(name=Sohan, dept=Admin, emplD=110)
            //第二次调用时,直接从缓存中拿
            System.out.println("第二次调用:");
            System.out.println(employeeCache.get("100"));//输出Employee(name=Mahesh, dept=Finance, emplD=100)
            System.out.println(employeeCache.get("103"));//输出Employee(name=Rohan, dept=IT, emplD=103)
            System.out.println(employeeCache.get("110"));//输出EmployeeEmployee(name=Sohan, dept=Admin, emplD=110)

            System.out.println("---------------------分割线-----------------------");
            //常用方法
            System.out.println("用getIfPresent获取key为104的值:"+employeeCache.getIfPresent("104"));//获取缓存中key对应的value,如果缓存没命中,返回null
            //如果缓存有值,覆盖,否则,新增
            employeeCache.put("104",new Employee("Aria","Boss","104"));
            //删除缓存
            employeeCache.invalidate("100");
            //获取缓存中元素的大概个数
            System.out.println("获取缓存中元素的大概个数为:"+employeeCache.size());
            //缓存的状态数据,包括(未)命中个数,加载成功/失败个数,总共加载时间,删除个数等。
            System.out.println("缓存的状态数据为:"+employeeCache.stats());//输出CacheStats{hitCount=3, missCount=4, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=966956, evictionCount=0}
            //asMap()方法获得缓存数据的ConcurrentMap快照
            System.out.println("把LoadingCache转换成concurrentMap:"+ employeeCache.asMap());//输出{103=Employee(name=Rohan, dept=IT, emplD=103), 110=Employee(name=Sohan, dept=Admin, emplD=110)}
            //刷新缓存,即重新取缓存数据,更新缓存
            employeeCache.refresh("110");
            //清除缓存
           employeeCache.invalidateAll();
            //清空所有数据
            employeeCache.cleanUp();


        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    //模拟从数据库拿数据
    private static Object getFromDatabase(String empId) {
        //局部变量,取一次,清除一次
        Employee e1 = new Employee("Mahesh", "Finance", "100");
        Employee e2 = new Employee("Rohan", "IT", "103");
        Employee e3 = new Employee("Sohan", "Admin", "110");

        Map database = new HashMap();
        database.put("100", e1);
        database.put("103", e2);
        database.put("110", e3);
        System.out.println("从数据库找empId为" + empId);
        return database.get(empId);
    }
}

@Data
@AllArgsConstructor
class Employee {
    private String name;
    private String dept;
    private String emplD;
}

十、Multimap

1、定义

可以含有多个一样的key

2、使用

关键方法:containsEntry、containsKey、containsValue;get、asMap、keySet、values;add、remove


    public static void main(String args[]){
        //初始化一个Multimap
        Multimap<String,String> multimap = ArrayListMultimap.create();
        multimap.put("lower", "a");
        multimap.put("lower", "b");
        multimap.put("lower", "c");
        multimap.put("lower", "d");
        multimap.put("lower", "e");
        multimap.put("upper", "A");
        multimap.put("upper", "B");
        multimap.put("upper", "C");
        multimap.put("upper", "D");

        System.out.println("是否包含键值对lower-a:"+multimap.containsEntry("lower", "a"));//输出 true
        System.out.println("是否包含键lower:"+multimap.containsKey("lower"));//输出 true
        System.out.println("是否包含值a:"+multimap.containsValue("a"));//输出 true
        System.out.println("multimap包含键值对数量:"+multimap.size());//输出9

        System.out.println("---------------分割线---------------");

        List<String> lowerList = (List<String>)multimap.get("lower");
        System.out.println("所有key为lower的值有:"+lowerList.toString());//输出[a, b, c, d, e]

        List<String> upperList = (List<String>)multimap.get("upper");
        System.out.println("所有key为lower的值有:"+upperList.toString());//输出[A, B, C, D]

        lowerList.add("f");
        upperList.remove("D");

        System.out.println("---------------分割线---------------");

        Map<String, Collection<String>> map = multimap.asMap();
        System.out.println("遍历整个multimap:");
       map.entrySet().forEach(entry->{
           String key = entry.getKey();
           Collection<String> value =  multimap.get(key);
           System.out.println(key + ":" + value);       //输出lower:[a, b, c, d, e, f] \n  upper:[A, B, C]
       });

        System.out.println("---------------分割线---------------");

        System.out.println("所有唯一key:");
        Set<String> keys =  multimap.keySet();
        keys.forEach(key-> System.out.print(key+" "));//输出lower upper


        System.out.println("\n所有的值:");
        Collection<String> values = multimap.values();
        System.out.println(values);//输出[a, b, c, d, e, f, A, B, C]
    }

posted on 2019-06-03 09:43  华哒妹妹  阅读(1213)  评论(0编辑  收藏  举报