Guava系列-集合

112 阅读5分钟

ImmutableSet && ImutableMap

不可变对象有很多优点,包括:

  • 当对象被不可信的库调用时,不可变形式是安全的;
  • 不可变对象被多个线程调用时,不存在竞态条件问题
  • 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
  • 不可变对象因为有固定不变,可以作为常量来安全使用。

创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。

示例
package guava.collect;

import com.google.common.collect.ImmutableSet;

/**
 * @author denny
 * @Description 不可变集合
 * @date 2018/7/26 下午3:16
 */
public class ImmutableCollectionsTest {
    /**
     * 1.直接申明静态集合
     */
    public static final ImmutableSet<String> COLOR_NAMES_1 = ImmutableSet.of(
        "red",
        "orange",
        "yellow",
        "green");
    /**
     * 2.防御式copy
     */
    public static final ImmutableSet<String> COLOR_NAMES_2 = ImmutableSet.copyOf(COLOR_NAMES_1);

    /**
     * 3.builder建造者模式
     */
    public static final ImmutableSet<String> COLOR_NAMES_3 = ImmutableSet.<String>builder().addAll(COLOR_NAMES_2).add("blue").build();


    public static void main(String[] args) {
        System.out.println("of:"+COLOR_NAMES_1);
        System.out.println("防御式copy:"+COLOR_NAMES_2);
        System.out.println("建造者模式:"+COLOR_NAMES_3);
        System.out.println("转换成list:"+COLOR_NAMES_3.asList());
    }
}
/*** 运行结果
*of:[red, orange, yellow, green]
*防御式copy:[red, orange, yellow, green]
*建造者模式:[red, orange, yellow, green, blue]
*转换成list:[red, orange, yellow, green, blue]
***/

Multiset

可以多次添加相等的元素,它和set最大的区别就是它可以对相同元素做一个计数的功能。 数据类型

abstract class AbstractMapBasedMultiset {
    private transient Map<E, Count> backingMap;
}

可以看到,Multiset是一个Map类型,它的value值记录了这个key出现了多少次。

实现类
MapMultiset是否支持null
HashMapHashMultiset
TreeMapTreeMultiset
LinkedHashMapLinkedHashMultiset
EnumMultiset
ImmutableMapImmutableMultiset
ConcurrentHashMapConcurrentMultiset
方法
方法描述
add(E element)向其中添加单个元素
add(E element,int occurrences)向其中添加指定个数的元素
count(Object element)返回给定参数元素的个数
remove(E element)移除一个元素,其count值 会响应减少
remove(E element,int occurrences)移除相应个数的元素
elementSet()将不同的元素放入一个Set中
entrySet()类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount()
setCount(E element ,int count)设定某一个元素的重复次数
setCount(E element,int oldCount,int newCount)将符合原有重复个数的元素修改为新的重复次数
retainAll(Collection c)保留出现在给定集合参数的所有的元素
removeAll(Collectionc)去除出现给给定集合参数的所有的元素
size()这个集合的大小,包含重复元素
示例
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

public class MultisetTest {

    public static void main(String[] args) {

        String str = "张三 李四 李四 王五 王五 王五";
        String[] strArr = str.split(" ");

        List<String> words = new ArrayList<String>(Arrays.asList(strArr));

        //创建一个HashMultiset集合,并将words集合数据放入
        Multiset<String> wordMultiset = HashMultiset.create();
        wordMultiset.addAll(words);

        //将不同的元素放在一个集合set中
        for (String key : wordMultiset.elementSet()) {
            //查看指定元素的个数
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("---------向集合中添加元素----------");
        //向集合中添加元素
        wordMultiset.add("李四");
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("-------向集合中添加若干个元素------");
        //向集合中添加若干个元素
        wordMultiset.add("赵六", 10);
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("--------向集合中移出一个元素------");
        //向集合中移出一个元素
        wordMultiset.remove("张三");
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("------向集合中移出若干个元素------");
        //向集合中移出若干个元素,如果元素的个数小于要移除的个数,则会把该元素移除光
        wordMultiset.remove("赵六",5);
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }


        System.out.println("-----设定某一个元素的重复次数-----");
        //设定某一个元素的重复次数
        wordMultiset.setCount("张三", 10);
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("-----设置复合元素的个数设为新的重复次数-----");
        //设置复合元素的个数设为新的重复次数(条件是第二个参数的数量要是实际数量一致,否则无效)
        wordMultiset.setCount("and", 1,0);
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }

        System.out.println("-------删除给定集合中的元素------");
        //删除给定集合中的元素
        wordMultiset.removeAll(words);
        for (String key : wordMultiset.elementSet()) {
            System.out.println(key + "-->" + wordMultiset.count(key));
        }
    }
}

Multimap

multimap和MultiSet的继承结果很相似,只不过在上层的接口是Multimap不是Multiset。

Multimap的特点其实就是可以包含有几个重复Key的value,你可以put进入多个不同value但是相同的key,但是又不是让后面覆盖前面的内容。

它的业务场景:当你需要构造像Map<K, List>或者Map<K, Set>这样比较复杂的集合类型的数据结构,来做相应的业务逻辑处理。那Multimap在合适不过。

实现类
ImplementationKeys 的行为类似Values的行为类似
ArrayListMultimapHashMap  ArrayList
HashMultimapHashMapHashSet
LinkedListMultimapLinkedHashMap*LinkedList*
LinkedHashMultimapLinkedHashMapLinkedHashSet
TreeMultimapTreeMapTreeSet
ImmutableListMultimapImmutableMapImmutableList
ImmutableSetMultimapImmutableMapImmutableSet 
方法
方法描述
put(K, V)
putAll(K, Iterable)
remove(K, V)
removeAll(K)
replaceValues(K, Iterable)
asMap()提供Map<K,Collection>形式的视图
entries()提供Collection<Map.Entry<K, V>>的视图(对SetMultimap,返回的是Set)
keySet()用Set表示Multimap中所有不同的键
keys()用Multiset表示Multimap中的所有键
values()提供Collection包含Multimap中的所有值
示例
public class MultimapTest {


        public static void main(String args[]){

              Multimap<String,String> multimap = ArrayListMultimap.create();

            multimap.put("lower", "a");
            multimap.put("lower", "b");
            multimap.put("lower", "c");

            multimap.put("upper", "A");
            multimap.put("upper", "B");

            List<String> lowerList = (List<String>)multimap.get("lower");
            //输出key为lower的list集合
            System.out.println("输出key为lower的list集合=========");
            System.out.println(lowerList.toString());
            lowerList.add("f");
            System.out.println(lowerList.toString());


            Map<String, Collection<String>> map = multimap.asMap();
            System.out.println("把Multimap转为一个map============");
            for (Map.Entry<String,  Collection<String>> entry : map.entrySet()) {
                String key = entry.getKey();
                Collection<String> value =  multimap.get(key);
                System.out.println(key + ":" + value);
            }

            System.out.println("获得所有Multimap的key值==========");
            Set<String> keys =  multimap.keySet();
            for(String key:keys){
                System.out.println(key);
            }

            System.out.println("输出Multimap所有的value值========");
            Collection<String> values = multimap.values();
            System.out.println(values);
        }
}
/**输出结果:
 *输出key为lower的list集合=========
 * [a, b, c]
 * [a, b, c, f]
 * 把Multimap转为一个map============
 * lower:[a, b, c, f]
 * upper:[A, B]
 * 获得所有Multimap的key值==========
 * lower
 * upper
 * 输出Multimap所有的value值========
 * [a, b, c, f, A, B]
  */

Table

结构类似于二维数组,它有两个支持所有类型的键:”行”和”列”。

bidirectional maps

bimap的作用很清晰:它是一个一一映射,可以通过key得到value,也可以通过value得到key。与HashMap对比,不仅key能保证唯一,value也能保证唯一。

实现类
ImplementationKeys 的行为类似Values的行为类似
HashBiMapHashMap  HashMap
EnumBiMapEnumEnum
ImmutableBiMap
方法
方法描述
inversekey, value反转
示例
public class bimapTest {
        public static void main(String args[]){

            //双向map
            BiMap<Integer,String> biMap = HashBiMap.create();
            biMap.put(1,"张三");
            biMap.put(2,"李四");
            biMap.put(3,"王五");
            biMap.put(4,"赵六");
            biMap.put(5,"李七");
            biMap.put(4,"小小");

            //通过key值得到value值(注意key里面的类型根据泛行
            String value = biMap.get(1);
            System.out.println("id为1的value值 --"+value);

            //通过value值得到key值
            int key = biMap.inverse().get("张三");
            System.out.println("张三key值 --"+key);

            //通过key值重复,那么vakue值会被覆盖。
            String valuename = biMap.get(4);
            System.out.println("id为4的value值 --"+valuename);
        }
}
/*运行结果:
 *id为1的value值 --张三
 *张三key值 --1
 *id为4的value值 --小小
 */

参考:
[1].www.cnblogs.com/qdhxhz/p/94… [2]. www.cnblogs.com/qdhxhz/p/94… [3]. www.cnblogs.com/qdhxhz/p/94…