[Google Guava]学习--新集合类型Multimap

每个有经验的Java程序员都在某处实现过Map<K, List<V>>或Map<K, Set<V>>,并且要忍受这个结构的笨拙。

假如目前有个需求是给两个年级添加5个学生,并且统计出一年级学生的信息:

public class MultimapTest {
    class Student {
        String name;
        int age;
    }

    private static final String CLASS_NAME_1 = "一年级";
    private static final String CLASS_NAME_2 = "二年级";

    Map<String, List<Student>> StudentsMap = new HashMap<String, List<Student>>();

    public void testStudent() {

        for (int i = 0; i < 5; i++) {
            Student student = new Student();
            student.name = "Tom" + i;
            student.age = 6;
            addStudent(CLASS_NAME_1, student);
        }
        for (int i = 0; i < 5; i++) {
            Student student = new Student();
            student.name = "Jary" + i;
            student.age = 7;
            addStudent(CLASS_NAME_2, student);
        }
        List<Student> class1StudentList = StudentsMap.get(CLASS_NAME_1);

        for (Student stu : class1StudentList) {
            System.out.println("一年级学生 name:" + stu.name + " age:" + stu.age);
        }
    }

    public void addStudent(String className, Student student) {
        List<Student> students = StudentsMap.get(className);
        if (students == null) {
            students = new ArrayList<Student>();
            StudentsMap.put(className, students);
        }
        students.add(student);
    }

    public static void main(String[] args) {
        MultimapTest multimapTest = new MultimapTest();
        multimapTest.testStudent();

    }
}

可以看到我们实现起来特别麻烦,需要检查key是否存在,不存在时则创建一个,存在时在List后面添加上一个。这个过程是比较痛苦的,如果希望检查List中的对象是否存在,删除一个对象,或者遍历整个数据结构,那么则需要更多的代码来实现。

Multimap 提供了一个方便地把一个键对应到多个值的数据结构。

我们可以这样理解Multimap:”键-单个值映射”的集合(例如:a -> 1 a -> 2 a ->4 b -> 3 c -> 5)

特点:不会有任何键映射到空集合:一个键要么至少到一个值,要么根本就不在Multimap中。

主要方法介绍:

  • put(K, V):添加键到单个值的映射
  • putAll(K, Iterable<V>):依次添加键到多个值的映射
  • remove(K, V):移除键到值的映射;如果有这样的键值并成功移除,返回true
  • removeAll(K):清除键对应的所有值,返回的集合包含所有之前映射到K的值,但修改这个集合就不会影响Multimap了
  • replaceValues(K, Iterable<V>):清除键对应的所有值,并重新把key关联到Iterable中的每个元素。返回的集合包含所有之前映射到K的值

Multimap的视图

  Multimap还支持若干强大的视图:

  • asMap为Multimap<K, V>提供Map<K,Collection<V>>形式的视图。返回的Map支持remove操作,并且会反映到底层的 Multimap,但它不支持put或putAll操作。更重要的是,如果你想为Multimap中没有的键返回null,而不是一个新的、可写的空集 合,你就可以使用asMap().get(key)。(你可以并且应当把asMap.get(key)返回的结果转化为适当的集合类型——如 SetMultimap.asMap.get(key)的结果转为Set,ListMultimap.asMap.get(key)的结果转为List ——Java类型系统不允许ListMultimap直接为asMap.get(key)返回List——译者注:也可以用Multimaps中的asMap静态方法帮你完成类型转换
  • entries用Collection<Map.Entry<K, V>>返回Multimap中所有”键-单个值映射”——包括重复键。(对SetMultimap,返回的是Set)
  • keySet用Set表示Multimap中所有不同的键。
  • keys用Multiset表示Multimap中的所有键,每个键重复出现的次数等于它映射的值的个数。可以从这个Multiset中移除元素,但不能做添加操作;移除操作会反映到底层的Multimap。
  • values()用 一个”扁平”的Collection<V>包含Multimap中的所有值。这有一点类似于 Iterables.concat(multimap.asMap().values()),但它直接返回了单个Collection,而不像 multimap.asMap().values()那样是按键区分开的Collection。

Multimap不是Map

  Multimap<K, V>不是Map<K,Collection<V>>,虽然某些Multimap实现中可能使用了map。它们之间的显著区别包括:

  • Multimap.get(key)总是返回非null、但是可能空的集合。这并不意味着Multimap为相应的键花费内存创建了集合,而只是提供一个集合视图方便你为键增加映射值——译者注:如果有这样的键,返回的集合只是包装了Multimap中已有的集合;如果没有这样的键,返回的空集合也只是持有Multimap引用的栈对象,让你可以用来操作底层的Multimap。因此,返回的集合不会占据太多内存,数据实际上还是存放在Multimap中。
  • 如果你更喜欢像Map那样,为Multimap中没有的键返回null,请使用asMap()视图获取一个Map<K, Collection<V>>。(或者用静态方法Multimaps.asMap()为ListMultimap返回一个Map<K, List<V>>。对于SetMultimap和SortedSetMultimap,也有类似的静态方法存在)
  • 当且仅当有值映射到键时,Multimap.containsKey(key)才会返回true。尤其需要注意的是,如果键k之前映射过一个或多个值,但它们都被移除后,Multimap.containsKey(key)会返回false。
  • Multimap.entries()返回Multimap中所有”键-单个值映射”——包括重复键。如果你想要得到所有”键-值集合映射”,请使用asMap().entrySet()。
  • Multimap.size()返回所有”键-单个值映射”的个数,而非不同键的个数。要得到不同键的个数,请改用Multimap.keySet().size()。

测试类:

  

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

public class MultimapTest {
    class Student {
        String name;
        int age;
    }

    private static final String CLASS_NAME_1 = "一年级";
    private static final String CLASS_NAME_2 = "二年级";

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

    public void testStudent() {

        for (int i = 0; i < 5; i++) {
            Student student = new Student();
            student.name = "Tom" + i;
            student.age = 6;
            multimap.put(CLASS_NAME_1, student);
        }
        for (int i = 0; i < 5; i++) {
            Student student = new Student();
            student.name = "Jary" + i;
            student.age = 7;
            multimap.put(CLASS_NAME_2, student);
        }

        for (Student stu : multimap.get(CLASS_NAME_1)) {
            System.out.println("一年级学生 name:" + stu.name + " age:" + stu.age);
        }
        //判断键是否存在
        if(multimap.containsKey(CLASS_NAME_1)){
            System.out.println("键值包含:"+CLASS_NAME_1);
        }
        //”键-单个值映射”的个数
        System.out.println(multimap.size());
        //不同键的个数
        System.out.print(multimap.keySet().size());
    }

    public static void main(String[] args) {
        MultimapTest multimapTest = new MultimapTest();
        multimapTest.testStudent();
    }
}
时间: 2024-10-26 00:59:05

[Google Guava]学习--新集合类型Multimap的相关文章

[Guava学习笔记]Collections: 不可变集合, 新集合类型

不可变集合 不接受null值. 创建:ImmutableSet.copyOf(set); ImmutableMap.of(“a”, 1, “b”, 2); public static final ImmutableSet<Color> GOOGLE_COLORS = ImmutableSet.<Color>builder() .addAll(WEBSAFE_COLORS) .add(new Color(0, 191, 255)) .build(); 可以有序(如ImmutableS

Guava学习笔记:Guava新增集合类型-Multimap

在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业务逻辑处理.例如: import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; public class MultimapTe

强大的Guava中的新集合类型: Multiset, Multimap, BiMap, Table, ClassToInstanceMap, RangeSet, RangeMap等

一 Multiset /** * 新类型集合: Multiset: Multiset就是可以保存多个相同的对象,并且无序 * 占据了List和Set之间的一个灰色地带 * 其他实现: TreeMultiset LinkedHashMultiset * ConcurrentHashMultiset * ImmutableMultiset */ @Test public void newList(){ HashMultiset<Integer> multiset = HashMultiset.cr

Guava新增集合类型-Multimap(3)

在日常的开发工作中,我们有的时候需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,以便做相应的业务逻辑处理. Multimap Guava的Multimap就提供了一个方便地把一个键对应到多个值的数据结构.让我们可以简单优雅的实现上面复杂的数据结构,让我们的精力和时间放在实现业务逻辑上,而不是在数据结构上,下面我们具体来看看Multimap的相关知识点. 调用Multimap.get(key)会返回这个

Swift学习笔记 - 教程学习三 集合类型 (Collection Types)

集合类型 (Collection Types) 本节及前面用到的for…in句型在后面的循环控制部分,if let 见基础篇.如果某些字符看不到,请到博客园来看原文.——新波 Swift提供了三种基本集合类型,数组(array).集合(set)和字典(dictionary).数组是一组按序排列的数据,集合是一组各不相同的无序数据,字典是一组与关键值相关联的无序数据.参见下图. 3.1 集合的可变性Mutability of Collections 与前面的字符串一样,赋值给变量的集合是可变的,赋

Swift 学习- 05 -- 集合类型

// 集合类型 // swift 提供 Arrays , Sets 和 Dictionaries 三种基本的集合类型用来存储数据 , 数组(Arrays) 是有序数据的集, 集合(Sets)是无序无重复数据的集, 字典(Dictionaries) 是无序的键值对的集 // swift 语言中的 Arrays, Sets 和 Dictionaries 中存储的数据值类型必须明确, 这意味着我们不能把不正确的数据类型插入其中, 同事这也说明我们完全可以取回值的类型非常自信 // 集合的可变性 //

Google Guava学习笔记——简介

Google Guava是什么东西?首先要追溯到2007年的“Google Collections Library”项目,它提供对Java 集合操作的工具类.后来Guava被进化为Java程序员开发必备的工具.Guava可以对字符串,集合,并发,I/O,反射进行操作. 在软件开发过程中,我们自认为可以什么都能做,我们本能的去写自己的类库来处理一些日常的问题.当然,我们认为自己写的代码是坚不可摧的,并且是经过单元测试的.实际上,我们没有我们认为的那么聪明,换句话说,它不在于你有多聪明,而是在于编写

Google Guava 学习记录《一》

Guava 在Google code 上地址:https://code.google.com/p/guava-libraries/ 首先为什么要学习这个库,在实习的时候看大神的代码很简洁,很多地方将一些琐碎凌乱的代码轻松解决,所以抱着试试看的心态搞搞吧. 第一部分:basic utilities null 问题的处理 理解Optional<T> ,首先要理解为什么出现这个.在Java中null其实代表的意思在不同的content下是不同的,比如一个值可能是null或者是真的不存在.在Map.g

Google Guava 学习记录《二》 Precondition

1 int i = 4; 2 int j = 5; 3 Preconditions.checkArgument(i>j,"i should bigger than j, but i is %s and j is %s",i,j); Exception in thread "main" java.lang.IllegalArgumentException: i should bigger than j, but i is 4 and j is 5 at com.