} } }

    Guava进修笔记:Guava新增凑集类型-Multimap

    添加时间:2013-7-9 点击量:

      在日常的开辟工作中,我们有的时辰须要机关像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 MultimapTest {

    Map
    <String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>();

    @Test
    public void testStudentScore(){

    forint i=10;i<20;i++){
    StudentScore studentScore
    =new StudentScore();
    studentScore.CourseId
    =1001+i;
    studentScore.score
    =100-i;
    addStudentScore(
    peida,studentScore);
    }

    System.out.println(
    StudentScoreMap:+StudentScoreMap.size());
    System.out.println(
    StudentScoreMap:+StudentScoreMap.containsKey(peida));

    System.out.println(
    StudentScoreMap:+StudentScoreMap.containsKey(jerry));
    System.out.println(
    StudentScoreMap:+StudentScoreMap.size());
    System.out.println(
    StudentScoreMap:+StudentScoreMap.get(peida).size());

    List
    <StudentScore> StudentScoreList=StudentScoreMap.get(peida);
    if(StudentScoreList!=null&&StudentScoreList.size()>0){
    for(StudentScore stuScore:StudentScoreList){
    System.out.println(
    stuScore one:+stuScore.CourseId+ score:+stuScore.score);
    }
    }
    }

    public void addStudentScore(final String stuName,final StudentScore studentScore) {
    List
    <StudentScore> stuScore = StudentScoreMap.get(stuName);
    if (stuScore == null) {
    stuScore
    = new ArrayList<StudentScore>();
    StudentScoreMap.put(stuName, stuScore);
    }
    stuScore.add(studentScore);
    }
    }

    class StudentScore{
    int CourseId;
    int score;
    }


      申明:想 Map<String, List<StudentScore>> StudentScoreMap = new HashMap<String, List<StudentScore>>()如许的数据布局,本身实现起来太麻烦,你须要搜检key是否存在,不存在时则创建一个,存在时在List后面添加上一个。这个过程是斗劲疾苦的,若是你搜检List中的对象是否存在,删除一个对象,或者遍历全部数据布局,那么则须要更多的代码来实现。


      Multimap


      Guava的Multimap就供给了一个便利地把一个键对应到多个值的数据布局。让我们可以简单优雅的实现上脸错杂的数据布局,让我们的精力和时候放在实现营业逻辑上,而不是在数据布局上,下面我们具体来看看Multimap的相干常识点。


      上方的代码和数据布局用Multimap来实现,代码布局清楚简单了很多吧,具体代码如下:



      @Test
    
    public void teststuScoreMultimap(){
    Multimap
    <String,StudentScore> scoreMultimap = ArrayListMultimap.create();
    forint i=10;i<20;i++){
    StudentScore studentScore
    =new StudentScore();
    studentScore.CourseId
    =1001+i;
    studentScore.score
    =100-i;
    scoreMultimap.put(
    peida,studentScore);
    }
    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.keys());
    }


      调用Multimap.get(key)会返回这个键对应的值的凑集的视图(view),没有对应凑集就返回空凑集。对于ListMultimap来说,这个办返回一个List,对于SetMultimap来说,这个办法就返回一个Set。批改数据是经由过程批改底层Multimap来实现的。例如:



    @Test
    
    public void teststuScoreMultimap(){
    Multimap
    <String,StudentScore> scoreMultimap = ArrayListMultimap.create();
    forint i=10;i<20;i++){
    StudentScore studentScore
    =new StudentScore();
    studentScore.CourseId
    =1001+i;
    studentScore.score
    =100-i;
    scoreMultimap.put(
    peida,studentScore);
    }
    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.keys());

    Collection
    <StudentScore> studentScore = scoreMultimap.get(peida);
    studentScore.clear();
    StudentScore studentScoreNew
    =new StudentScore();
    studentScoreNew.CourseId
    =1034;
    studentScoreNew.score
    =67;
    studentScore.add(studentScoreNew);

    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.keys());
    }


        Multimap也支撑一系列强大的视图功能:
      1.asMap把自身Multimap<K, V>映射成Map<K, Collection<V>>视图。这个Map视图支撑remove和批改操纵,然则不支撑put和putAll。严格地来讲,当你传入参数是不存在的key,并且你返回的是null而不是一个空的可批改的凑集的时辰就可以调用asMap().get(key)。(你可以强迫转型asMap().get(key)的成果类型-对SetMultimap的成果转成Set,对ListMultimap的成果转成List型-然则直接把ListMultimap转成Map<K, List<V>>是不可的。)
      2.entries视图是把Multimap里所有的键值对以Collection<Map.Entry<K, V>>的情势显现。
      3.keySet视图是把Multimap的键凑集作为视图
      4.keys视图返回的是个Multiset,这个Multiset是以不反复的键对应的个数作为视图。这个Multiset可以经由过程支撑移除操纵而不是添加操纵来批改Multimap。
      5.values()视图能把Multimap里的所有值“平坦”成一个Collection<V>。这个操纵和Iterables.concat(multimap.asMap().values())很类似,只是它返回的是一个完全的Collection。


      尽管Multimap的实现用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因为两者有明显差别:
      1.Multimap.get(key)必然返回一个非null的凑集。但这不默示Multimap应用了内存来接洽关系这些键,相反,返回的凑集只是个容许添加元素的视图。
      2.若是你喜好像Map那样当不存在键的时辰要返回null,而不是Multimap那样返回空凑集的话,可以用asMap()返回的视图来获得Map<K, Collection<V>>。(这种景象下,你得把返回的Collection<V>强转型为List或Set)。
      3.Multimap.containsKey(key)只有在这个键存在的时辰才返回true。
      4.Multimap.entries()返回的是Multimap所有的键值对。然则若是须要key-collection的键值对,那就得用asMap().entries()。
      5.Multimap.size()返回的是entries的数量,而不是不反复键的数量。若是要获得不反复键的数量就得用Multimap.keySet().size()。



      @Test
    
    public void teststuScoreMultimap(){
    Multimap
    <String,StudentScore> scoreMultimap = ArrayListMultimap.create();
    forint i=10;i<20;i++){
    StudentScore studentScore
    =new StudentScore();
    studentScore.CourseId
    =1001+i;
    studentScore.score
    =100-i;
    scoreMultimap.put(
    peida,studentScore);
    }
    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.keys());

    Collection
    <StudentScore> studentScore = scoreMultimap.get(peida);
    StudentScore studentScore1
    =new StudentScore();
    studentScore1.CourseId
    =1034;
    studentScore1.score
    =67;
    studentScore.add(studentScore1);

    StudentScore studentScore2
    =new StudentScore();
    studentScore2.CourseId
    =1045;
    studentScore2.score
    =56;
    scoreMultimap.put(
    jerry,studentScore2);

    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.keys());


    for(StudentScore stuScore : scoreMultimap.values()) {
    System.out.println(
    stuScore one:+stuScore.CourseId+ score:+stuScore.score);
    }

    scoreMultimap.remove(
    jerry,studentScore2);
    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.get(jerry));

    scoreMultimap.put(
    harry,studentScore2);
    scoreMultimap.removeAll(
    harry);
    System.out.println(
    scoreMultimap:+scoreMultimap.size());
    System.out.println(
    scoreMultimap:+scoreMultimap.get(harry));
    }


      Multimap的实现


      Multimap供给了雄厚的实现,所以你可以用它来调换法度里的Map<K, Collection<V>>,具体的实现如下:
      Implementation            Keys 的行动类似          Values的行动类似
      ArrayListMultimap         HashMap                     ArrayList
      HashMultimap               HashMap                     HashSet
      LinkedListMultimap        LinkedHashMap              LinkedList
      LinkedHashMultimap      LinkedHashMap                LinkedHashSet
      TreeMultimap                TreeMap                          TreeSet
      ImmutableListMultimap  ImmutableMap                 ImmutableList
      ImmutableSetMultimap  ImmutableMap                 ImmutableSet


      
      以上这些实现,除了immutable的实现都支撑null的键和值。
      1.LinkedListMultimap.entries()能保持迭代时的次序。


      2.LinkedHashMultimap保持插入的次序,以及键的插入次序。
      要重视并不是所有的实现都正真实现了Map<K, Collection<V>>!(尤其是有些Multimap的实现为了最小话开销,应用了自定义的hash table)

    所有随风而逝的都属于昨天的,所有历经风雨留下来的才是面向未来的。—— 玛格丽特·米切尔 《飘》
    分享到: