Java高效編程類庫-Guava入門與實踐


Guava的類特別多,就將常用的進行展開記錄,以後需要用到了再補充

Guava簡介

Guava工程包含了若干個被Google的Java項目廣泛依賴的核心庫,例如:集合、緩存、原生類型支持、併發庫、通用註解、字符串處理、I/0等等

引入依賴

	 <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>27.1-jre</version>
    </dependency>

對null處理 :Optional類

Optional 類是一個可以爲null的容器對象
Optional 類的引入很好的解決空指針異常

JDK8中,將Optional類引入到了Java 8的類庫,所以可以直接使用JDK的Optional類

創建Optional對象的三種方式

        //創建空的Optional對象
        Optional.empty();

        //使用非null值創建Optional對象
        Optional.of("zhangsan");

        //使用任意值創建Optional對象
        Optional<Object> optional = Optional.ofNullable("zhangsan");

常用方法:

  • 判斷是否引用缺失(null)
		/**
         * 判斷是否引用缺失(是否爲空)
         * 不建議使用
         */
        optional.isPresent();
  • 如果引用存在(非nulll),則進行系列操作
		/**
         * 如果引用存在,即不爲null,進行操作(如打印)
         * 類似的有map。flatmap,filter
         */
        optional.ifPresent(System.out::println);
  • 引用缺失時的三種操作
		optional.orElse("引用缺失");//缺失修改值爲某值


        optional.orElseGet(() -> {//缺失時直接進行相應操作(如返回提示)
            return "自定義引用缺失";
        });


        optional.orElseThrow(() -> {//缺失時可以拋出異常
            throw new RuntimeException("引用缺失異常");
        });
  • 實際應用實踐

創建一個方法通過流打印集合內容

	public static void stream(List<String> list) {
        //如果list爲空,會拋出異常
        list.stream().forEach(System.out::println);
    }

如果list爲空,則會拋出異常,stream初始化失敗
使用Optional進行優化:

	public static void stream(List<String> list) {
        //如果list不爲空,初始化流,如果爲空,初始化一個空的流
        Optional.ofNullable(list)
                .map(List::stream)
                .orElseGet(Stream::empty)
                .forEach(System.out::println);
    }
  1. 首先通過 Optional.ofNullable(list)創建一個Optional對象
  2. 如果Optional對象引用存在,則執行map中的list.stream()方法
  3. 如果Optional對象引用缺失,則執行 Stream.empty()方法創建一個空的對象
  4. 最後再打印輸出

不可變集合 :Immutable*類

不可變對象的優點:

  • 當對象被不可信的庫調用時,是安全的
  • 不可變對象在多線程環境下安全
  • 不可變集合不需要考慮變化,可以節省時間和空間
  • 不可變對象常作爲常量來安全使用

Immutabl*是一系列的不可變集合,包括了很多很多的類,使用起來其實大同小異,一下就以ImmutableSet說明下他的創建
在這裏插入圖片描述

創建不可變對象的三種方式(以ImmutableSet爲例)

		List<Integer>list = new ArrayList<Integer>(){
            {add(1);}
            {add(2);}
            {add(3);}
        };
		//通過已存在集合創建
        ImmutableSet.copyOf(list);

        //通過初始值直接創建不可變集合
        ImmutableSet.of(1, 2, 3, 4, 5);

        //以builder方式創建
        ImmutableSet immutableSet = ImmutableSet.builder()
                .add(1)
                .addAll(Sets.newHashSet(2, 3, 4))
                .add(5)
                .build();

構建好的Immutable*的對象不具有添加和刪除的接口
在這裏插入圖片描述

新的集合類型 Multiset接口

類似的還有和Multimap接口,一下以Multiset爲例

Multiset是一種介於Set和List直接的一種數據結構,兩種角度理解Multiset

  • 沒有元素順序限制的ArrayList
    • add(E):添加單個元素
    • iterator():返回一個迭代器
    • size():返回所有元素的總個數(包括重複的)
  • Map<E,Integer>,鍵爲元素,值爲計數
    • count(Object):返回給的元素的計數
    • entrySet():相當於Map中的entrySet
    • elementSet():相當於Map中的KeySet

接口的五種實現類:

  • HashMultiset
  • TreeMultiset
  • LinkedHashSet
  • ConcurrentHashMultiset
  • mmutableMultiset

業務中的實踐:

實現字符統計的功能

/**
 * 〈使用Mutiset統計古詩文字出現頻率〉
 *
 * @author Chkl
 * @create 2020/4/21
 * @since 1.0.0
 */
public class MultisetTest {

    private static final String text =
            "《山坡羊·潼關懷古》\n" +
                    "峯巒如聚,波濤如怒,山河表裏潼關路。 \n" +
                    "望西都,意躊躇。\n" +
                    "傷心秦漢經行處,宮闕萬間都做了土。 \n" +
                    "興,百姓苦。亡,百姓苦。";

    @Test
    public void handle(){
        //創建Multiset
        Multiset<Character> multiset = HashMultiset.create();

        //stirng to char
        char[] chars = text.toCharArray();

        //遍歷數組,加入到multiset
        Chars.asList(chars)
                .stream()
                .forEach(charitem->{
                    multiset.add(charitem);
                });

        System.out.println(multiset.size());
        for (Character c : multiset.elementSet()){
            System.out.println(c+" "+multiset.count(c));
        }
    }
}

常用工具集 :Sets、Lists類

Sets工具類常用方法: 並集、交集、差集、分解集合中所有的子集、求兩個集合的笛卡爾積

Lists工具類常用方法: 反轉、拆分

演示實踐:

初始化兩個set

    private static final Set set1 =
            Sets.newHashSet(1, 2, 3, 4);
    private static final Set set2 =
            Sets.newHashSet(4, 5, 6);
  • 求並集

    @Test
    public void union() {
        Set<Integer> set = Sets.union(set1, set2);
        System.out.println(set);
    }
  • 求交集
	@Test
    public void intersection() {
        Set<Integer> set = Sets.intersection(set1, set2);
        System.out.println(set);
    }
  • 求差集
    元素屬於a但不屬於b
	@Test
    public void difference() {
        Set<Integer> set = Sets.difference(set1, set2);
        System.out.println(set);
    }
  • 求相對差集
    元素屬於a但不屬於b 或元素屬於b但不屬於a
	@Test
    public void symmetricDifference() {
        Set<Integer> set = Sets.symmetricDifference(set1, set2);
        System.out.println(set);
    }
  • 拆解集合(求所有子集)
	@Test
    public void powerSet() {
        Set<Set<Integer>> set = Sets.powerSet(set1);
        System.out.println(JSON.toJSONString(set));
    }
  • 求笛卡爾積
 	@Test
    public void cartesianProduct() {
        Set<List<Integer>> set = Sets.cartesianProduct(set1, set2);
        System.out.println(JSON.toJSONString(set));
    }

初始化一個List

private static final List<Integer> list =
            Lists.newArrayList(1, 2, 3, 4, 5, 6, 7);
  • 按指定長度拆分
 	@Test
    public void partition() {
        List<List<Integer>> partition = Lists.partition(list, 3);
        System.out.println(JSON.toJSONString(partition));
    }
  • 反轉集合
	@Test
    public void reverse() {
        List<Integer> reverse = Lists.reverse(list);
        System.out.println(JSON.toJSONString(reverse));
    }

IO操作: Files類

對字節流和字符流操作的封裝

  • ByteStreams:提供對InputStream和OutputStream針對字節流的操作
  • CharStreams:提供Reader和Writer針對字符流的操作

針對源(Source)和匯(Sink)的抽象

  • 源(可讀的):ByteSource/CharSource
  • 匯(可寫的):ByteSink/CharSink

Files中封裝了很多好用的方法,這裏主要記錄一下源與匯的使用

實踐案例:
通過源與匯實現文件拷貝,源與匯是比較高級的封裝,直接使用不需要對輸入輸出流進行創建和關閉

	 /**
     * 通過源與匯實現文件拷貝
     */
    @Test
    public void copyFile() throws IOException {
        /**
         * 創建對應的Source和Sink
         */
        CharSource charSource = Files.asCharSource(
                new File("lib/FileCopy.java"), Charsets.UTF_8);
        CharSink charSink = Files.asCharSink(
                new File("outTest/out.txt"), Charsets.UTF_8);

        /**
         * 拷貝,不需要創建連接和關閉連接
         */
        charSource.copyTo(charSink);
        
    }

更多的方法在具體使用時查Api吧 ,源與匯還是挺好用的

最後

Guava用起來非常強大,方法也非常多,找到一個算是目錄的網站,可以去系統的看一看Api 直達

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章