Guava提供的Map扩展操作代码示例

HashBasedTable(双键Map)

双键数据结构类型,底层由LinkedHashMap实现,官方定义可以将两个Key分别示意为rowKeycolumnKey,且提供了按rowKey获取或者按columnKey获取的API,注意无论是rowKey、columnKey还是value都不能为null值。

HashBasedTable实际上本身也是HashMap<R, HashMap<C,V>>的结构,因此,rowKey的查找性能要高于columnKey的查找。

public static void table() {
        HashBasedTable<String, String, String> table = HashBasedTable.create();
        // put操作
        table.put("研发部", "张三", "20");
        table.put("研发部", "李四", "21");
        table.put("产品部", "王五", "22");
        table.put("销售部", "赵六", "23");
        table.put("行政部", "小明", "24");

        // 按rowKey和columnKey获取value
        String value = table.get("研发部", "张三");
        // 输出结果:20
        System.out.println(value);

        // 按columnKey获取,rowKey和value就分别为Map中的Key和Value
        Map<String, String> columnKey = table.column("张三");
        // 输出结果:{研发部=20}
        System.out.println(columnKey);

        // 按rowKey获取,columnKey和value就分别为Map中的Key和Value
        Map<String, String> rowKey = table.row("研发部");
        // 输出结果:{张三=20, 李四=21}
        System.out.println(rowKey);

        // 以column为Key,转成原始的Map套Map的格式
        Map<String, Map<String, String>> toColumnMap = table.columnMap();
        // 输出结果:{张三={研发部=20}, 李四={研发部=21}, 王五={产品部=22}, 赵六={销售部=23}, 小明={行政部=24}}
        System.out.println(toColumnMap);

        // 以row为Key,转成原始的Map套Map的格式
        Map<String, Map<String, String>> toRowMap = table.rowMap();
        // 输出结果:{研发部={张三=20, 李四=21}, 产品部={王五=22}, 销售部={赵六=23}, 行政部={小明=24}}
        System.out.println(toRowMap);

        // 按columnKey转Set集合
        Set<String> toColumnKeySet = table.columnKeySet();
        // 输出结果:[张三, 李四, 王五, 赵六, 小明]
        System.out.println(toColumnKeySet);

        // 按rowKey转Set集合
        Set<String> toRowKeySet = table.rowKeySet();
        // 输出结果:[研发部, 产品部, 销售部, 行政部]
        System.out.println(toRowKeySet);

        // 按values转成集合
        Collection<String> values = table.values();
        // 输出结果:[20, 21, 22, 23, 24]
        System.out.println(values);

        // 各种contains判断
        table.containsColumn("");
        table.containsRow("");
        table.containsValue("");
        table.contains("", "");

    }

内部实际上也是Map套Map的结构

public static <R, C, V> HashBasedTable<R, C, V> create() {
  return new HashBasedTable<>(new LinkedHashMap<R, Map<C, V>>(), new Factory<C, V>(0));
}

执行put操作时,也是先判断rowKey是否存在于LinkedHashMap中,不存在则put,存在则直接取出,然后再put -> columnKey

public V put(R rowKey, C columnKey, V value) {
  checkNotNull(rowKey);
  checkNotNull(columnKey);
  checkNotNull(value);
  return getOrCreate(rowKey).put(columnKey, value);
}

`factory`实际上也是一个`LinkedHashMap`
private Map<C, V> getOrCreate(R rowKey) {
  Map<C, V> map = backingMap.get(rowKey);
  if (map == null) {
    map = factory.get();
    backingMap.put(rowKey, map);
  }
  return map;
}

类似的,除了HashBasedTable之外,也有支持排序的TreeBasedTable,以及不可变的ImmutableTable,同样他们都不是线程安全的,使用时应当注意。

HashBiMap(双向查找Map)

由两个Hash表组成,不但支持由Key查找Value,还支持由Value查找Key,同时KeyValue都可以为null

public static void biMap() {
    HashBiMap<String, String> biMap = HashBiMap.create();
    biMap.put("研发部", "张三");
    // 由于Key和Value可以互相转换,所以正常情况下Value不能重复
    // biMap.put("产品部", "张三"); 会报错,也可以强制替换,biMap.forcePut("产品部", "张三")
    biMap.get("研发部");
    BiMap<String, String> inverse = biMap.inverse();
    inverse.get("张三");
    inverse.put("产品部", "李四");
    // 输出结果:李四
    System.out.println(inverse.get("产品部"));
	// 输出结果:{研发部=张三, 李四=产品部}
	System.out.println(biMap);
	// 输出结果:{张三=研发部, 产品部=李四}
	System.out.println(inverse);
}

由于需要需要两张Hash表,所以每次put时,除了完成正向Mapput之外,还需完成反向Mapput

根据拿到正向MapKey对应的Value,再做为反向MapKey填入

private void insert(BiEntry<K, V> entry, @CheckForNull BiEntry<K, V> oldEntryForKey) {
  int keyBucket = entry.keyHash & mask;
  entry.nextInKToVBucket = hashTableKToV[keyBucket];
  hashTableKToV[keyBucket] = entry;
  int valueBucket = entry.valueHash & mask;
  entry.nextInVToKBucket = hashTableVToK[valueBucket];
  hashTableVToK[valueBucket] = entry;
  if (oldEntryForKey == null) {
    entry.prevInKeyInsertionOrder = lastInKeyInsertionOrder;
    entry.nextInKeyInsertionOrder = null;
    if (lastInKeyInsertionOrder == null) {
      firstInKeyInsertionOrder = entry;
    } else {
      lastInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
    }
    lastInKeyInsertionOrder = entry;
  } else {
    entry.prevInKeyInsertionOrder = oldEntryForKey.prevInKeyInsertionOrder;
    if (entry.prevInKeyInsertionOrder == null) {
      firstInKeyInsertionOrder = entry;
    } else {
      entry.prevInKeyInsertionOrder.nextInKeyInsertionOrder = entry;
    }
    entry.nextInKeyInsertionOrder = oldEntryForKey.nextInKeyInsertionOrder;
    if (entry.nextInKeyInsertionOrder == null) {
      lastInKeyInsertionOrder = entry;
    } else {
      entry.nextInKeyInsertionOrder.prevInKeyInsertionOrder = entry;
    }
  }
  size++;
  modCount++;
}

双向查找的Map,同样也有不可变的ImmutableBiMap,使用双向查找Map时由于同时维护了两个Map,并且正反操作的都是同一个对象,这就导致在实际使用时会非常容易出错,因此建议慎用!

TreeRangeMap(范围Map)

基于RangeMapTreeMap实现,KeyValue都不能为null,可以用于替换if...else,switch等条件语句

private static void rangeMap() {
    RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
    rangeMap.put(Range.closedOpen(0, 18), "未成年");
    rangeMap.put(Range.closed(18, 30), "青年");
    rangeMap.put(Range.openClosed(30, 60), "中年");
	// 输出结果:青年
    System.out.println(rangeMap.get(18));
	// 输出结果:{[0..18)=未成年, [18..30]=青年, (30..60]=中年}
	System.out.println(rangeMap.asMapOfRanges());
	// 输出结果:[18..30]=青年
	System.out.println(rangeMap.getEntry(20));
	// 输出结果:[0..60]
	System.out.println(rangeMap.span());
}

TreeRangeMap的外层是一个TreeMap,其中Key记录着Range的左区间,Value是一个RangeMap

@Override
public void put(Range<K> range, V value) {
  if (!range.isEmpty()) {
    checkNotNull(value);
    remove(range);
    entriesByLowerBound.put(range.lowerBound, new RangeMapEntry<K, V>(range, value));
  }
}

基于TreeMap是有序性,直接通过floorEntry找到小于等于Key的最大映射

@Override
@CheckForNull
public V get(K key) {
  Entry<Range<K>, V> entry = getEntry(key);
  return (entry == null) ? null : entry.getValue();
}
@Override
@CheckForNull
public Entry<Range<K>, V> getEntry(K key) {
  Entry<Cut<K>, RangeMapEntry<K, V>> mapEntry =
      entriesByLowerBound.floorEntry(Cut.belowValue(key));
  if (mapEntry != null && mapEntry.getValue().contains(key)) {
    return mapEntry.getValue();
  } else {
    return null;
  }
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值