栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java--HashMap--创建/排序/遍历/重写equels和hashCode

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java--HashMap--创建/排序/遍历/重写equels和hashCode

原文网址:Java--HashMap--创建/排序/遍历/重写equels和hashCode_IT利刃出鞘的博客-CSDN博客

简介

        本文用实例介绍HashMap的操作,包括:方法大全、创建、排序(按照key排序和按照value排序)、按插入顺序存放、遍历方法及其性能、重写equels和hashCode。

方法大全

返回类型

方法和描述

示例

void

clear()

从该Map中删除所有的映射(可选操作)。

default V

compute(K key, BiFunction remappingFunction)

通过指定键来进行处理。

若我们返回null,则在map中移除对应的key-value对。

Map map = new HashMap<>();
map.put("aa", 1);
map.put("bb", 1);

Integer compute = map.compute("cc", (k, v) -> (v == null) ? 0 : 2 * v);
System.out.println(compute);  //0
System.out.println(map);    //{cc=0, aa=1, bb=1}

default V

computeIfAbsent(K key, Function mappingFunction)

如果指定的键尚未与值相关联(或映射到 null ),则尝试使用给定的映射函数计算其值,并将其加入到此map中。

若我们返回null,则在map中移除对应的key-value对。

Map map = new HashMap<>();
map.put("aa", 1);
map.put("bb", 1);

Integer computeIfAbsent = map.computeIfAbsent("cc", k -> {
    return 0;
});
System.out.println(computeIfAbsent);  //0
System.out.println(map);   //{cc=0, aa=1, bb=1}

default V

computeIfPresent(K key, BiFunction remappingFunction)

如果指定的密钥的值存在且非空,则尝试计算给定密钥及其当前映射值的新映射。

若我们返回null,则在map中移除对应的key-value对。

Map map = new HashMap<>();
map.put("aa", 1);
map.put("bb", 1);

Integer computeIfPresent1 = map.computeIfPresent("bb", (k, v) -> {
    return v * 2;
});
System.out.println(computeIfPresent1);  //2
System.out.println(map);  //{aa=1, bb=2}

boolean

containsKey(Object key)

如果此映射包含指定键的映射,则返回 true 。

boolean

containsValue(Object value)

如果此地图将一个或多个键映射到指定的值,则返回 true 。

Set

Entry>

entrySet()

返回此地图中包含的映射的Set视图。

boolean

equals(Object o)

将指定的对象与此映射进行比较以获得相等性。

default void

forEach(BiConsumer action)

对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。

V

get(Object key)

如果有该key:返回到指定键所映射的值。如果没有该key,返回null;

default V

getOrDefault(Object key, V defaultValue)

如果有该key:返回到指定键所映射的值。如果没有该key,返回defaultValue;

Map map = new HashMap<>();
map.put("aa", 1);
map.put("bb", 1);

Integer getOrDefault = map.getOrDefault("cc", 0);
System.out.println(getOrDefault);   //0
System.out.println(map);    //{aa=1, bb=1}

int

hashCode()

返回此地图的哈希码值。

boolean

isEmpty()

如果此地图不包含键值映射,则返回 true 。

Set

keySet()

返回此地图中包含的键的Set视图。

default V

merge(K key, V value, BiFunction remappingFunction)

如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联。

V

put(K key, V value)

将指定的值与该映射中的指定键相关联(可选操作)。

若key已经有value,则覆盖。

void

putAll(Map m)

将指定map的所有映射复制到此映射(可选操作)。

default V

putIfAbsent(K key, V value)

如果指定的键尚未与某个值相关联(或映射到 null )将其与给定值相关联并返回 null ,否则返回当前值。

V

remove(Object key)

如果存在(从可选的操作),从该地图中删除一个键的映射。

default boolean

remove(Object key, Object value)

仅当指定的密钥当前映射到指定的值时删除该条目。

default V

replace(K key, V value)

只有当目标映射到某个值时,才能替换指定键的条目。

default boolean

replace(K key, V oldValue, V newValue)

仅当当前映射到指定的值时,才能替换指定键的条目。

default void

replaceAll(BiFunction function)

将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。

int

size()

返回此地图中键值映射的数量。

Collection

values()

返回此地图中包含的值的Collection视图。

Function  //只能接受一个参数

java/util/function/Function.java

package org.example.a;

import java.util.function.Function;

public class Demo {
    public static void main(String[] args) {
        Function fun1= arg -> arg * arg;
        Integer apply = fun1.apply(10);
        System.out.println(apply);          // 100
    }
}

运行结果

100

BiFunction  //可接受两个参数

java/util/function/BiFunction.java

package org.example.a;

import java.util.function.BiFunction;

public class Demo {
    public static void main(String[] args) {
        BiFunction fun2 = (arg1, arg2) -> arg1 + arg2;
        Integer sum = fun2.apply(10, 20);
        System.out.println(sum);        // 30
    }
}

运行结果

30
创建

法1:匿名内部类

HashMap map = new HashMap() {{
        put("name", "test");  
        put("age", "20"); 
    }};

缺点

1.内存泄露隐患

  非静态内部类/ 匿名内部类包含了外围实例的引用, 如果拥有比 外部类更长的生命周期,有内存泄露隐患。

2.如果这个对象要串行化,可能会导致串行化失败。

  1. 此种方式是匿名内部类的声明方式,所以引用中持有着外部类的引用。所以当时串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。
  2. 上例中,其实是声明了一个继承自HashMap的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化Hashset或者HashMap的子类的,从而导致串行化失败。

解决办法:重新初始化为一个HashMap对象:

HashMap map = new HashMap() {{
        put("name", "test");  
        put("age", "20"); 
    }};
HashMap newMap = new HashMap(map);

这样就可以正常初始化了。

法2:静态方法

public class Demo{
    private static final Map myMap;
    static {
        myMap = new HashMap();
        myMap.put("a", "b");
        myMap.put("c", "d");
    }
}

法3:第三方包Guava

Map left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
//或者
Map test = ImmutableMap.builder()
    .put("k1", "v1")
    .put("k2", "v2")
    ...
    .build();
排序已有数据 按key排序

使用stream进行排序(按key升序/降序)

package org.example.a;

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("ad", "dd");
        map.put("bc", "ee");
        map.put("cb", "ff");
        for (Map.Entry entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        Map linkedHashMap = new linkedHashMap<>();
        // 默认按照升序排列
        map.entrySet().stream().sorted(Map.Entry.comparingByKey())
                .forEach(o -> linkedHashMap.put(o.getKey(), o.getValue()));
        for (Map.Entry entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        Map linkedHashMap1 = new linkedHashMap<>();
        // 自定义排序(降序)
        map.entrySet().stream().sorted(Map.Entry.comparingByKey(new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        })).forEach(o -> linkedHashMap1.put(o.getKey(), o.getValue()));
        for (Map.Entry entry : linkedHashMap1.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

执行结果

bc:ee
ad:dd
cb:ff

ad:dd
bc:ee
cb:ff

cb:ff
bc:ee
ad:dd

HashMap转TreeMap自定义排序(按key升序/降序)

package org.example.a;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class Demo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("ad", "dd");
        map.put("bc", "ee");
        map.put("cb", "ff");
        for (Map.Entry entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();
        // 默认按照升序排序
        Map map1 = new TreeMap<>();
        map.forEach(map1::put);
        for (Map.Entry entry : map1.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        // 自定义排序(降序)
        Map map2 = new TreeMap<>(new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        map.forEach(map2::put);
        for (Map.Entry entry : map2.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

执行结果

bc:ee
ad:dd
cb:ff

ad:dd
bc:ee
cb:ff

cb:ff
bc:ee
ad:dd
按value排序

使用stream进行排序(按value升序/降序)

package org.example.a;

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("ad", "dd");
        map.put("bc", "ee");
        map.put("cb", "ff");
        for (Map.Entry entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        Map linkedHashMap = new linkedHashMap<>();
        // 默认按照升序排列
        map.entrySet().stream().sorted(Map.Entry.comparingByValue())
                .forEach(o -> linkedHashMap.put(o.getKey(), o.getValue()));
        for (Map.Entry entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        Map linkedHashMap1 = new linkedHashMap<>();
        // 自定义排序(降序)
        map.entrySet().stream().sorted(Map.Entry.comparingByValue(new Comparator() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        })).forEach(o -> linkedHashMap1.put(o.getKey(), o.getValue()));
        for (Map.Entry entry : linkedHashMap1.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

执行结果

bc:ee
ad:dd
cb:ff

ad:dd
bc:ee
cb:ff

cb:ff
bc:ee
ad:dd

 借助List进行排序(按value升序/降序)

        原理:将待排序Map中的所有元素置于一个列表中,接着使用Collections的一个静态方法 sort(List list, Comparator c) 来排序列表,同样是用比较器定义比较规则。排序后的列表中的元素再依次装入Map,为了肯定的保证Map中元素与排序后的List中的元素的顺序一致,使用了linkedHashMap数据类型。

        本处只写升序代码,降序只是调换个顺序而已。

package org.example.a;

import java.util.*;

public class Demo {
    public static void main(String[] args) {
        Map map = new HashMap<>();
        map.put("ad", "dd");
        map.put("bc", "ee");
        map.put("cb", "ff");
        for (Map.Entry entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();

        Map sortedMap = new linkedHashMap<>();
        List> entryList = new ArrayList>(
                map.entrySet());
        Collections.sort(entryList, new Comparator>() {
            @Override
            public int compare(Map.Entry me1, Map.Entry me2) {
                return me1.getValue().compareTo(me2.getValue());
            }
        });
        for (Map.Entry stringStringEntry : entryList) {
            sortedMap.put(stringStringEntry.getKey(), stringStringEntry.getValue());
        }

        for (Map.Entry entry : sortedMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

运行结果

bc:ee
ad:dd
cb:ff

ad:dd
bc:ee
cb:ff
按插入顺序存放

使用HashMap

package org.example.a;

import java.util.*;

public class Demo{
    public static List arrayList = new ArrayList();
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        hashMap.put("name1", "josan1");
        hashMap.put("name2", "josan2");
        hashMap.put("name3", "josan3");
        
        Set> set = hashMap.entrySet();
        Iterator> iterator = set.iterator();
        while(iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ", value:" + value);
        }
    }
}

执行结果(未按照插入顺序输出)

key:name3, value:josan3
key:name2, value:josan2
key:name1, value:josan1

使用linkedHashMap

package org.example.a;

import java.util.*;

public class Demo{
    public static List arrayList = new ArrayList();
    public static void main(String[] args) {
        Map hashMap = new linkedHashMap();
        hashMap.put("name1", "josan1");
        hashMap.put("name2", "josan2");
        hashMap.put("name3", "josan3");

        Set> set = hashMap.entrySet();
        Iterator> iterator = set.iterator();
        while(iterator.hasNext()) {
            Map.Entry entry = iterator.next();
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            System.out.println("key:" + key + ", value:" + value);
        }
    }
}

执行结果(按照插入顺序输出)

key:name1, value:josan1
key:name2, value:josan2
key:name3, value:josan3 

遍历方法及其性能

遍历方法

方法

说明/示例

for each map.entrySet()

Map map = new HashMap();

for (Entry entry : map.entrySet()) {

  entry.getKey();

  entry.getValue();

}

调用map.entrySet()的集合迭代器

Iterator> iterator = map.entrySet().iterator();

while (iterator.hasNext()) {

  entry.getKey();

  entry.getValue();

}

for each map.keySet(),再调用get获取

Map map = new HashMap();

for (String key : map.keySet()) {

  map.get(key);

}

遍历方法对比

三种遍历方式的性能测试及对比

测试环境:Windows7 32位系统 3.2G双核CPU 4G内存,Java 7,Eclipse -Xms512m -Xmx512m

测试结果:

map size10,000100,0001,000,0002,000,000
for each entrySet2ms6ms36ms91ms
for iterator entrySet0ms4ms35ms89ms
for each keySet1ms6ms48ms126ms

遍历方式结果分析(由上表可知):

  • for each entrySet与for iterator entrySet性能等价
  • for each keySet由于要再调用get(key)获取值,比较耗时(若hash散列算法较差,会更加耗时)
  • 在循环过程中若要对map进行删除操作,只能用for iterator entrySet(在HahsMap非线程安全里介绍)。

HashMap entrySet源码

private final class EntryIterator extends HashIterator> {
  public Map.Entry next() {
    return nextEntry();
  }
}

HashMap keySet源码

private final class KeyIterator extends HashIterator {
  public K next() {
    return nextEntry().getKey();
  }
}

由源码可知:

        keySet()与entrySet()都是返回set的迭代器。父类相同,只是返回值不同,因此性能差不多。只是keySet()多了一步根据key get value的操作而已。get的时间复杂度取决于for循环的次数,即hash算法。

public V get(Object key) {
  if (key == null)
    return getForNullKey();
  Entry entry = getEntry(key);
  return null == entry ? null : entry.getValue();
}

final Entry getEntry(Object key) {
  int hash = (key == null) ? 0 : hash(key);
  for (Entry e = table[indexFor(hash, table.length)];
     e != null;
     e = e.next) {
    Object k;
    if (e.hash == hash &&
      ((k = e.key) == key || (key != null && key.equals(k))))
      return e;
  }
  return null;
}

 使用场景总结

方法

使用场景

for each map.entrySet()

循环中需要key、value,但不对map进行删除操作

调用map.entrySet()的集合迭代器

循环中需要key、value,且要对map进行删除操作

for each map.keySet()

循环中只需要key

重写equals和hashCode

其他网址

如何重写hashCode()和equals()方法_王鸿飞的专栏-CSDN博客
如何编写出高质量的 equals 和 hashcode 方法? - 掘金

其他网址

Java HashMap 初始化赋值 (不建议)_AlbenXie的博客-CSDN博客_hashmap 初始化
JAVA构造MAP并初始化MAP_dujianxiong的博客-CSDN博客_java map初始化

java8 map根据key排序和根据value排序_weixin_40841731的博客-CSDN博客_map根据key排序
Java Map 按Key排序和按Value排序_Ricky-CSDN博客_java map key 排序

Java HashMap三种循环遍历方式及其性能对比实例分析_java_脚本之家
Java迭代器(转)(iterator详解以及和for循环的区别) - redcoatjk - 博客园

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/352074.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号