• Java工具库Guava的不可变集合和新集合类型Multiset、Multimap、BiMap、RangeSet、RangeMap等的使用示例


    场景

    Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验:

    Java核心工具库Guava介绍以及Optional和Preconditions使用进行非空和数据校验_霸道流氓气质的博客-CSDN博客_guava 校验

    在上面引入Guava的基础上。学习其不可变集合和新集合类型的使用

    不可变集合

    1、当对象被不可信的库调用时,不可变形式是安全的。

    2、不可变对象被多个线程调用时,不存在竞态条件问题。

    3、不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比他们的可变形式有更好的内存利用率。

    4、不可变对象因为固定不变,可以作为常量来安全使用。

    注:

    博客:
    https://blog.csdn.net/badao_liumang_qizhi 
    关注公众号
    霸道的程序猿
    获取编程相关电子书、教程推送与免费下载。

    不可变集合的创建

    1、copyOf方法

    1.         //创建不可变集合的方式
    2.         List<String> list = new ArrayList<String>(){{
    3.             this.add("badao");
    4.             this.add("de");
    5.             this.add("chengxvyuan");
    6.         }};
    7.         //1、copyOf方法
    8.         ImmutableList<String> strings = ImmutableList.copyOf(list);
    9.         System.out.println(strings);//[badao, de, chengxvyuan]
    10.         list.add("add");
    11.         System.out.println(strings);//[badao, de, chengxvyuan]

    并且当原集合改变时,copy的不会改变

    2、of方法

    1.         ImmutableList<String> of = ImmutableList.of("a", "b", "d", "c");
    2.         System.out.println(of);//[a, b, d, c]

    3、Builder工具

    1.         ImmutableSet<Object> add = ImmutableSet.builder()
    2.                 .addAll(list)
    3.                 .add("add")
    4.                 .build();
    5.         System.out.println(add);//[badao, de, chengxvyuan, add]

    ImmutableSortedSet有序不可变集合

    对于有序不可变集合,排序在构造集合时就完成

    1.         ImmutableSortedSet<String> of2 = ImmutableSortedSet.of("a", "d", "a", "c", "b", "a");
    2.         System.out.println(of2);//[a, b, c, d]

    asList视图

    所有不可变集合都有一个asList()方法提供ImmutableList视图

    1.         System.out.println(ImmutableSet.of("a","a","b","c").asList());//[a, b, c]
    2.         System.out.println(ImmutableSet.of("a","a","b","c").asList().get(0));//a

    新集合类型

    Multiset

    Multiset,可以多次添加相等的元素,Multiset元素顺序是无关的,Multiset{a,a,b} 与{a,b,a}是相等的

    可以将其看做是没有元素顺序限制的ArrayList

    1、添加单个给定元素

    1.         Multiset<String> multiSet = HashMultiset.create();
    2.         multiSet.add("badao");
    3.         multiSet.add("badao");
    4.         multiSet.add("de");
    5.         multiSet.add("de");

    2、获取元素个数

            System.out.println(multiSet.size());//4

    3、添加多个给定元素

    1.         List<String> list = new ArrayList<String>(){{
    2.             this.add("badao");
    3.             this.add("de");
    4.             this.add("chengxvyuan");
    5.         }};
    6.         //size获取元素个数
    7.         System.out.println(multiSet.size());//4
    8.         //添加多个给定元素
    9.         multiSet.addAll(list);
    10.         System.out.println(multiSet.size());//7

    4、iterator()返回一个迭代器,包含Multiset的所有元素(包括重复元素)

    1.         Iterator<String> it = multiSet.iterator();
    2.         while (it.hasNext()) {
    3.             System.out.println(it.next());
    4.         }

    也可以将其看做是Map 键为元素,值为计数

    1、count(Object)返回给定元素的计数

    System.out.println("badao元素的计数为:"+multiSet.count("badao"));//badao元素的计数为:3

    2、elementSet() Multiset不重复元素的集合,类型为Set

    System.out.println(multiSet.elementSet());//[badao, de, chengxvyuan]

    3、entrySet()和Map的entrySet类似,返回Set> 其中包含的Entry支持getElement()和getCount()方法

    1.         multiSet.entrySet().forEach(stringEntry -> {
    2.             System.out.println(stringEntry.getElement()+stringEntry.getCount());
    3.         });

    4、add(E,int) 增加给定元素在Multiset中的计数

    1.         System.out.println( multiSet.count("badao"));//3
    2.         multiSet.add("badao",3);
    3.         System.out.println(multiSet.count("badao"));//6

    5、设置给定元素在Multiset中的计数

    1.         multiSet.setCount("badao",1);
    2.         System.out.println(multiSet.count("badao"));//1

    SortedMultiset

    SortedMultiset是Multiset接口的变种,它支持高效地获取指定范围的子集

    1.         SortedMultiset sortedMultiset = TreeMultiset.create();
    2.         sortedMultiset.add(0);
    3.         sortedMultiset.add(1);
    4.         sortedMultiset.add(2);
    5.         sortedMultiset.add(2);
    6.         sortedMultiset.add(3);
    7.         sortedMultiset.add(5);
    8.         sortedMultiset.add(6);
    9.         sortedMultiset.add(8);
    10.         sortedMultiset.add(9);
    11.         //统计在05以内的数量,包含0,不包含5
    12.         int size = sortedMultiset.subMultiset(0, BoundType.CLOSED, 5, BoundType.OPEN).size();
    13.         int size1 = sortedMultiset.size();
    14.         // 创建一个数值格式化对象
    15.         NumberFormat numberFormat = NumberFormat.getInstance();
    16.         // 设置精确到小数点后2
    17.         numberFormat.setMaximumFractionDigits(2);
    18.         String result = numberFormat.format((float)size/(float)size1);
    19.         System.out.println(result);//0.56

    Multimap

    Multimap 是把键映射到任意多个值的一般方式,不会有任何键映射到空集合:一个键要么至少到一个值,要么不存在Multimap中

    1、Multimap的创建

    Multimap multimap = HashMultimap.create();

    2、添加键到单个值的映射

    1.         multimap.put("a",1);
    2.         multimap.put("a",2);
    3.         multimap.put("a",3);
    4.         multimap.put("b",3);

    3、get(key)以集合形式返回键所对应的值视图,即使没有任何对应的值,也会返回空集合

    1.         Collection a = multimap.get("a");
    2.         System.out.println(a);//[1, 2, 3]

    4、putAll(K,Iterable) 依次添加键到多个值的映射

    1.         multimap.putAll("c",
    2.                 new ArrayList(){
    3.                     {
    4.                         this.add(1);
    5.                         this.add(2);
    6.                         this.add(3);
    7.                         this.add(4);
    8.                     }
    9.                 });
    10.         System.out.println(multimap.get("c"));//[1, 2, 3, 4]

    5、remove(K,V)移除键到值的映射;如果有这样的键值并成功移除,返回true

    1.         multimap.remove("c",1);
    2.         System.out.println(multimap.get("c"));//[2, 3, 4]

    6、removeAll(K) 清除键对应的所有值,返回的集合包含所有之前映射到K的值,但修改这个集合就不会影响到Multimap了

    1.         //multimap.removeAll("c");
    2.         System.out.println(multimap.get("c"));//[]

    7、replaceValues(K,Iterable)清除键对应的所有值,并重新把key关联到Iterable中的每个元素。

    1.         multimap.replaceValues("c",new ArrayList(){{
    2.             this.add(6);
    3.             this.add(7);
    4.         }});
    5.         System.out.println(multimap.get("c"));//[6, 7]

    8、asMap为Multimap提供Map形式的视图。返回的Map支持remove操作,并且会

    反映到底层的Multimap,但它不支持put或putAll操作。

    1.         Map map = multimap.asMap();
    2.         System.out.println(map);//{a=[1, 2, 3], b=[3], c=[6, 7]}

    9、entries用Collection>返回Multimap中所有“键-单个值映射”,包括重复键

    1.         Collection entries = multimap.entries();
    2.         System.out.println(entries);//[a=1, a=2, a=3, b=3, c=6, c=7]

    10、keySet用Set表示Multimap中所有不同的键

    System.out.println(multimap.keySet());//[a, b, c]

    11、keys用Multiset表示Multimap中的所有键,每个键重复出现的次数等于它映射的值的个数

    可以从这个Multiset中移除元素,但不能做添加操作;移除操作会反映到底层的Multimap

    System.out.println(multimap.keys());//[a x 3, b, c x 2]

    12、values()用一个扁平的Collection包含Multimap中的所有值。

    System.out.println(multimap.values());//[1, 2, 3, 3, 6, 7]

    BiMap

    BiMap是特殊的Map: 可以用inverse()反转BiMap的键值映射,保证值是唯一的,因此valus()返回Set而不是普通的Collection

    1、在BiMap中,如果你想把键映射到已经存在的值,会抛出IllegalArgumentException

    1.         HashBiMap<String,Integer> biMap = HashBiMap.create();
    2.         biMap.put("a",1);
    3.         //biMap.put("b",1);//java.lang.IllegalArgumentException

    2、如果对特定的值,想要强制替换它的键,使用forcePut

    1.         System.out.println(biMap.get("a"));//1
    2.         biMap.forcePut("b",1);
    3.         System.out.println(biMap.get("b"));//1

    3、put和Inverse

    1.         HashBiMap<String,Integer> biMap2 = HashBiMap.create();
    2.         biMap2.put("a",1);
    3.         biMap2.put("a",2);
    4.         System.out.println(biMap2);//{a=2}
    5.         BiMap<Integer, String> inverse = biMap2.inverse();
    6.         System.out.println(inverse);//{2=a}

    Table

    Guava提供了Table,它有两个支持所有类型的键:“行“和”列“

    1、put

    1.         HashBasedTable<Integer, Integer, String> table = HashBasedTable.create();
    2.         table.put(1,1,"java");
    3.         table.put(1,2,"c");
    4.         table.put(2,1,"c++");
    5.         table.put(2,2,"c#");

    2、row(r)用Map返回给定“行”的所有列,对这个map进行的写操作也将写入Table中

    1.         Map<Integer, String> row = table.row(1);
    2.         System.out.println(row);//{1=java, 2=c}

    3、rowMap() 用Map> 表现Table

    1.         Map<Integer, Map<Integer, String>> integerMapMap = table.rowMap();
    2.        System.out.println(integerMapMap);//{1={1=java, 2= c},2={1=c++, 2=c#}}

    4、rowKeySet()返回行的集合set

    1.         Set<Integer> integers = table.rowKeySet();
    2.         System.out.println(integers);//[1, 2]

    5、column 返回指定列

    System.out.println(table.column(2));//{1=c, 2= c#}

    6、columnMap 用Map> 表现Table

    System.out.println(table.columnMap());//{1={1=java, 2= c++},2={1=c, 2=c#}}

    7、columnKeySet返回所有列的集合set

    System.out.println(table.columnKeySet());//[1, 2]

    8、cellSet()用元素类型为Table.Cell的Set表现Table

    System.out.println(table.cellSet());//[(1,1)=java, (1,2)=c, (2,1)=c++, (2,2)=c#]

    ClassToInstanceMap

    ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象。

    ClassToInstabceMap额外声明了两个方法 T getInstance(Class) 和 T putInstance(Class,T),从而避免强制类型转换,同时保证了类型安全

    1.         ClassToInstanceMap<Number> instanceMap = MutableClassToInstanceMap.create();
    2.         instanceMap.putInstance(Integer.class,Integer.valueOf(0));
    3.         System.out.println(instanceMap.getInstance(Integer.class));//0

    RangeSet

    RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时,所有相连的区间会被合并,空区间会被忽略

    1、创建和添加

    1.         RangeSet<Integer> rangeSet = TreeRangeSet.create();
    2.         rangeSet.add(Range.closed(1,10));
    3.         System.out.println(rangeSet);//[[1..10]]
    4.         rangeSet.add(Range.closedOpen(11,15));
    5.         System.out.println(rangeSet);//[[1..10], [11..15)]
    6.         rangeSet.add(Range.closedOpen(15,20));
    7.         System.out.println(rangeSet);//[[1..10], [11..20)]
    8.         rangeSet.add(Range.openClosed(0,0));
    9.         System.out.println(rangeSet);//[[1..10], [11..20)]
    10.         rangeSet.remove(Range.open(5,10));
    11.         System.out.println(rangeSet);//[[1..5], [10..10], [11..20)]

    2、complement()返回RangeSet的补集视图

    System.out.println(rangeSet.complement());//[(-∞..1), (5..10), (10..11), [20..+∞)]

    3、subRangeSet(Range)返回RangeSet与Range的交集视图

    System.out.println(rangeSet.subRangeSet(Range.closedOpen(15,30)));//[[15..20)]

    4、asRanges()用Set表现RangeSet,这样可以遍历其中的Range

    1.         Set<Range<Integer>> ranges = rangeSet.asRanges();
    2.         System.out.println(ranges);//[[1..5], [10..10], [11..20)]

    5、contains(C) 判断RangeSet中是否有任何区间包含给定元素

    1.         System.out.println(rangeSet.contains(6));//false
    2.         System.out.println(rangeSet.contains(11));//true

    6、rangeContaining(C)返回包含给定元素的区间;若没有这样的区间,则返回null

    1.         System.out.println(rangeSet.rangeContaining(6));//null
    2.         System.out.println(rangeSet.rangeContaining(11));//[11..20)

    7、encloses判断RangeSet中是否有任何区间包括给定区间

    1.         System.out.println(rangeSet.encloses(Range.closedOpen(11,15)));//true
    2.         System.out.println(rangeSet.encloses(Range.closedOpen(6,9)));//false
    3.         System.out.println(rangeSet.encloses(Range.closedOpen(15,25)));//false

    8、span返回包含RangeSet中所有区间的最小区间

    System.out.println(rangeSet.span());//[1..20)

    RangeMap

    RangeMap描述了“不想交的、非空的区间” 到特定值的映射,和RangeSet不同,RangeMap不会和并相邻的映射,即使相邻的区间映射到相同的值

    1、创建和put

    1.         RangeMap<Integer,String> rangeMap = TreeRangeMap.create();
    2.         rangeMap.put(Range.closed(1,10),"badao");
    3.         System.out.println(rangeMap);//[[1..10]=badao]
    4.         rangeMap.put(Range.open(3,6),"de");
    5.         System.out.println(rangeMap);//[[1..3]=badao, (3..6)=de, [6..10]=badao]
    6.         rangeMap.put(Range.open(10,20),"chengxvyuan");
    7.         System.out.println(rangeMap);//[[1..3]=badao, (3..6)=de, [6..10]=badao, (10..20)=chengxvyuan]
    8.         rangeMap.remove(Range.closed(5,11));
    9.         System.out.println(rangeMap);//[[1..3]=badao, (3..5)=de, (11..20)=chengxvyuan]

    2、asMapOfRanges() 用Map表现RangeMap,这可以用来遍历RangeMap

    1.         Map<Range<Integer>, String> rangeStringMap = rangeMap.asMapOfRanges();
    2.         System.out.println(rangeStringMap);//{[1..3]=badao, (3..5)=de, (11..20)=chengxvyuan}

    3、subRangeMap(Range)用RangeMap类型返回RangeMap与给定Range的交集视图

    System.out.println(rangeMap.subRangeMap(Range.closed(2,4)));//{[2..3]=badao, (3..4]=de}

  • 相关阅读:
    BetterDisplay Pro v1.4.15(显示器管理管理软件)
    12.Vue2和Vue3中的全局属性
    【Reinforcement Learning】价值学习
    视频怎么制作动图?分享简单的视频制作gif方法
    esp32开发板学习
    上线服务时遇到的一个SSLHandshakeException错误
    parsel的使用
    动态表单获取某一项值
    MySQL的主从复制与读写分离详解
    Flutter应用-使用sqflite升级数据库
  • 原文地址:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127900306