浅读java.util.Map及其实现类(一)

时间:2022-06-19 15:48:12

Map解读


Map是集合框架( java collections framwork)中的一员


集合框架中包含list  / set  / queue  /  map
list , set , queue 是 collection 的子接口
map不属于collection , map是一个独立的集合接口
  
collections - >  collection -> list
                                                -> set
                                                -> queue
                       ->  map  
                                                

Map是一种键值对的存储关系


其中每个Key对应一个value,其实这里我们可以把List看到一个带有数字key(索引index)的map,当然虽然他们都是java.util包下的集合类但是他俩并无关联
Key是一个不可重复的,每个Key只能映射到一个value,当然他是支持泛型的
Map取代了过期的Dictionary类,因为他是个抽象类而不是一个接口

Map提供了三种集合视图


Set<Map.Entry<K,V>>   map.entrySet() 
返回一组键值映射集合set是collection的子接口可以使用iterator
Set<K>  keySet() 
返回一组键集合 
Collection<V>  values() 
返回一组值集合
通过以上三组不同功能的视图我们可以得到collection并进行遍历等操作

Map的所有已知实现类


AbstractMap 
Attributes 
AuthProvider 
ConcurrentHashMap 
ConcurrentSkipListMap 
EnumMap 
HashMap 
Hashtable 
IdentityHashMap 
LinkedHashMap 
PrinterStateReasons 
Properties 
Provider 
RenderingHints 
SimpleBindings 
TabularDataSupport 
TreeMap
UIDefaults
WeakHashMap 
这些我们在之后的文章中来一起学习和深入了解

Map jdk1.8新特性


1.8支持了default , default具体用法这里就不在说明了
我们在1.8下,查看map源码,发现了很多@since 1.8的新方法,并且都是default修饰
   
//当找不到Key所映射的value时,返回defaultValue
default V getOrDefault(Object key, V defaultValue

//遍历map配合lambda
default void forEach(BiConsumer<? super K, ? super V> action)

//替换所有k中v都为指定值
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) 

//获取指定key下value,如果key未有映射,则增加k,v映射并返回null,如key有映射则返回key所映射的value
default V putIfAbsent(K key, V value) 

//删除指定Key下value,匹配get(Key)是否等于param.value或判断key是否存在于map,如果为真再调用map.remove(Key)
default boolean remove(Object key, Object value)

//替换key下原value,匹配get(Key)是否与param.oldValue相等或判断key存在,再调用map.put(Key,newValue)
default boolean replace(K key, V oldValue, V newValue)

//不再判断param.value与旧值的关系,只确认map.get(key)!=null值或key存在于map中则map.put(Key,value)
default V replace(K key, V value)

//如果目标Key指向了一个value那么后面的操作全部忽略,如果Key不存在则将mappingFunction的结果插入到Key中
default V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction)

//如果key指向的value存在而且非空则将remappingFunction的结果与他映射,反之则返回null
default V computeIfPresent(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction)

//key没有指向的value则创建一个新key,key有指向的vallue则覆盖他
default V compute(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction)

//如果key映射为null则直接用value,否则用remappingFunction的结果与key映射
default V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction)

Demo实现

import java.util.HashMap;
import java.util.Map;

/**
* Java Map
*
* @see
* @author Allen 2017年6月13日
*
*/
public class IsMap {
static Map<String, Object> map;
static void ini() {
map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("d", 4);
map.put("e", 5);
}

public static void main(String[] args) {
ini();
// getOrDefault
System.out.println("#getOrDefault");
System.out.println(String.valueOf(map.getOrDefault("a", 0)));
System.out.println(String.valueOf(map.getOrDefault("z", 0)));
System.out.print("\n");

// forEach
System.out.println("#forEach");
printMap();

// replaceAll
System.out.println("#replaceAll");
map.replaceAll((k, v) -> 99);
printMap();

// putIfAbsent
System.out.println("#putIfAbsent");
ini();
System.out.println(map.putIfAbsent("a", 33));
System.out.println(map.putIfAbsent("z", 99));
System.out.println(map.putIfAbsent("a", 1));
printMap();

// remove
System.out.println("#remove");
System.out.println(map.remove("a", 43));
System.out.println(map.remove("a", 1));
printMap();

// replace
ini();
System.out.println("#replace(k,ov,nv)");
System.out.println(map.replace("a", 2, 333));
System.out.println(map.replace("a", 1, 333));
printMap();

// replace
ini();
System.out.println("#replace(k,v)");
System.out.println(map.replace("a", 2));
System.out.println(map.replace("a", 1));
printMap();

// computeIfAbsent
ini();
System.out.println("#computeIfAbsent");
System.out.println(map.computeIfAbsent("a", k -> 1 + k));
System.out.println(map.computeIfAbsent("abc", k -> 2 + k));
System.out.println(map);

// computeIfPresent
ini();
System.out.println("#computeIfPresent");
System.out.println(map.computeIfPresent("a", (k, v) -> 1998));
System.out.println(map.computeIfPresent("zzz", (k, v) -> 998));
System.out.println(map);

// compute
ini();
System.out.println("#compute");
System.out.println(map.compute("a", (k, v) -> 555));
System.out.println(map.compute("aaaa", (k, v) -> 555));
System.out.println(map);

// merge
ini();
System.out.println("#merge");
System.out.println(map.merge("a", 3, (constant, value) -> constant.toString().concat(value.toString())));
System.out.println(map);
}

private static void printMap() {
map.forEach((k, v) -> System.out.print("[ k:" + k + "/" + "v:" + v + " ]"));
System.out.print("\n\n");
}

}
#日志打印结果
#getOrDefault
1
0

#forEach
[ k:a/v:1 ][ k:b/v:2 ][ k:c/v:3 ][ k:d/v:4 ][ k:e/v:5 ]

#replaceAll
[ k:a/v:99 ][ k:b/v:99 ][ k:c/v:99 ][ k:d/v:99 ][ k:e/v:99 ]

#putIfAbsent
1
null
1
[ k:a/v:1 ][ k:b/v:2 ][ k:c/v:3 ][ k:d/v:4 ][ k:e/v:5 ][ k:z/v:99 ]

#remove
false
true
[ k:b/v:2 ][ k:c/v:3 ][ k:d/v:4 ][ k:e/v:5 ][ k:z/v:99 ]

#replace(k,ov,nv)
false
true
[ k:a/v:333 ][ k:b/v:2 ][ k:c/v:3 ][ k:d/v:4 ][ k:e/v:5 ]

#replace(k,v)
1
2
[ k:a/v:1 ][ k:b/v:2 ][ k:c/v:3 ][ k:d/v:4 ][ k:e/v:5 ]

#computeIfAbsent
1
2abc
{a=1, b=2, abc=2abc, c=3, d=4, e=5}
#computeIfPresent
1998
null
{a=1998, b=2, c=3, d=4, e=5}
#compute
555
555
{a=555, b=2, c=3, d=4, e=5, aaaa=555}
#merge
13
{a=13, b=2, c=3, d=4, e=5}

扩展知识点 BiFunction & Function 了解


因为在map的新函数中增加了很多lambda的东西,其中BiFunction & Function 参数我们在此了解一下

@FunctionalInterface


BiFunction与Function接口头部都包含@Functionallnterface注释
被@Functionallnterface注释的接口在满足齐格式规范情况下都可以用于处理lambda表达式
如果一个接口没有@Functionallnterface注释,但只要齐满足了lambda表达式处理接口的规范,也会被编译器认为可以接收并处理lambda表达式
简单一个例子:
//这里我们定义个function
@FunctionalInterface
public interface MyFunction<T, U, Z, R> {

/**
* 这里是必须的否则会报错,T,U,Z都代表入参,R也就是泛型中最后一个值为返回值
*
* @param t
* @param u
* @param z
* @return
*/
R apply(T t, U u, Z z);
}
new IsMap<String, String, String, String>().aa("z", "k", "n", (a, b, c) -> a + b + c);void goFunction(T t, U u, Z z, MyFunction<T, U, Z, R> myfunction) {    System.out.println(myfunction.apply(t, u, z));}//输出结果zkn

BiFunction & Function

BiFunction.java
@FunctionalInterface
public interface BiFunction<T, U, R> {

/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @return the function result
*/
R apply(T t, U u);

default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t, U u) -> after.apply(apply(t, u));
}
}
Function.java
@FunctionalInterface
public interface Function<T, R> {

/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}


default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}


static <T> Function<T, T> identity() {
return t -> t;
}
}
可见不仅仅包含了apply的固定格式,还有若干个default方法
Objects.requireNonNull判断是否为空
空的话会抛出NPE
compose与andThen从不过是执行顺序不同的组合罢了
Function<String, String> a = e -> e +"一二";
Function<String, String> b = e -> e + "三四";
System.out.println(a.andThen(b).apply("#"));
System.out.println(a.compose(b).apply("#"));
输出结果
#一二三四
#三四一二


结语


map基础概念以及涉及到jdk1.8的新方法和Function相关内容就在这里了。下一期会对map中的实现类进行分析