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} open(a, b)
[a..b] {x | a <= x <= b} closed(a, b)
[a..b) {x | a <= x < b} closedOpen(a, b)
(a..b] {x | a < x <= b} openClosed(a, b)
(a..+∞) {x | x > a} greaterThan(a)
[a..+∞) {x | x >= a} atLeast(a)
(-∞..b) {x | x < b} | lessThan(b)
(-∞..b] {x | x <= b} atMost(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]
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM