java基于文件的map实现_java集合-Map

Java8增强的Map集合

Key-value都可以是任何引用类型的数据,Map的Key不允许重复即同一个Map对象的任何两个key通过equals方法比较总是返回false。

如果把Map里的所有key放在一起来看,他们就组成了一个Set集合:所有key没有顺序,key与key之间不能重复,实际上Map确实包含了一个keySet方法,用来返回Map里所有key组成的Set集合。

Map的这些实现类和子接口中key集的存储形式和对应Set集合中元素的存储形式完全相同。

Set与Map之间的关系非常密切。虽然Map中放的元素时key-value对,Set集合中放的元素时单个对象,但如果把key-value对中的value当成key的附庸:key在那里,value就跟在那里,这样就可以像对待Set一样来对待Map了。事实上,Map提供了一个Entry内部类来封装key-value对,而计算Entry存储时则只考虑Entry封装的key。从java源码来看,java是先实现了Map,然后通过包装一个所有value都为null的Map就实现了Set集合。

如果把Map里的所有value放在一起来看,他们又非常类似于一个List:元素与元素之间可以重复,但每个元素可以根据索引来查找,只是Map中的索引不再使用整数值,而是以另一个对象作为索引。

public class MapTest {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("java", 1);

map.put("python", 2);

map.put("hadoop", 3);

//{python=2, java=1, hadoop=3}

System.out.println(map);

//如果当前Map中已经有一个与该Key相等的key-value对,则新的key-value会覆盖原来的key-value对。并返回之前被覆盖的value

Integer put = map.put("java", 4);

System.out.println(put);//1

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

System.out.println(map2);

//python=2

//java=4

//hadoop=3

}

for(Object obj : map.keySet()) {

System.out.println(obj);//python java hadoop

}

}

}

Java8为Map新增加的方法

public class NewMapTest {

public static void main(String[] args) {

Map map = new HashMap<>();

map.put("123", 456);

//{123=456}

System.out.println(map);

/**

* compute 和 computeIfAbsent 和 computeIfPresent总结

*

* compute 如果函数式接口中的返回值不为null,那就是用接口中返回值来覆盖原value

* 如果接口中返回值为null,那么就删除此map对

* 如果原value为null,那就用接口中返回值覆盖原value

* computeIfAbsent

* 如果函数式接口中的返回值不为null,而且原value不为null,那么不做改变

* 如果接口中返回值为null,不做改变

* 如果原value为null,那么就使用接口中的返回值覆盖原value

*/

/**

* map.compute(key, remappingFunction)

* 该方法使用remappingFunction根据原来key-value对计算一个新value

* 只要新value不为null,就使用新value覆盖原来value;

* 如果原来value不为null,但新value为null,则删除原key-value对;

* 如果原value,新value同时为null,那么方法不改变任何key-value对,直接返回null;

*/

/*

Integer compute = map.compute("123", (key,value) -> Integer.parseInt(key));

System.out.println(compute);//123

System.out.println(map);//{123=123}

Integer compute = map.compute("123", (key,value) -> null);

System.out.println(map);//{}

*/

/*

map.put("1234", null);

Integer compute = map.compute("1234", (key,value) -> 0);

System.out.println(compute);//0

System.out.println(map);//{123=456, 1234=0}

*/

/**

* Absent 缺席

* map.computeIfAbsent(key, mappingFunction)

* 如果传给该方法的key参数在Map中对应的value为null,则使用mappingFunction根据原来key,value计算一个新的结果

* 如果计算结果不为null,则用计算结果覆盖原有的value。如果原Map原来不包括该Key,那么该方法可能会添加一组key-value对。

*/

/*

map.put("1234", null);

map.computeIfAbsent("1234", (key) -> Integer.parseInt(key));

System.out.println(map);//{123=456, 1234=1234}

*/

/*

Integer computeIfAbsent = map.computeIfAbsent("1231", (e) -> Integer.parseInt(e));

System.out.println(computeIfAbsent);//1231

System.out.println(map);//{123=456, 1231=1231}

*/

/*

Integer computeIfAbsent = map.computeIfAbsent("123", (e) -> Integer.parseInt("123123123"));

System.out.println(computeIfAbsent);//456

System.out.println(map);//{123=456}

*/

/**

* Present 提出;介绍;呈现;赠送

* map.computeIfPresent(key, remappingFunction)

* 如果传给该方法的key参数在Map中对应的value不为null,该方法使用remappingFunction根据原key-value计算一个新结果,

* 如果计算结果不为null,则使用该结果覆盖原来的value,

* 如果计算结果为null,则删除原key-value对

*/

/*

Integer computeIfPresent = map.computeIfPresent("123", (key,value) -> 0);

System.out.println(computeIfPresent);//0

System.out.println(map);//{123=0}

*/

/*

Integer computeIfPresent = map.computeIfPresent("1234", (Key,value) -> 0);

System.out.println(computeIfPresent);//null

System.out.println(map);//{123=456}

*/

/*

map.put("1234", null);

Integer computeIfPresent = map.computeIfPresent("1234", (key,value) -> 12);

System.out.println(computeIfPresent);//null

System.out.println(map);//{123=456, 1234=null}

*/

/*

Integer computeIfPresent = map.computeIfPresent("123", (key,value) -> null);

System.out.println(computeIfPresent);//null

System.out.println(map);//{}

*/

//获取指定key对应的value,如果key不存在那么就返回指定value

Integer orDefault = map.getOrDefault("1234", 452);

System.out.println(orDefault);//452

/**

* 该方法会先根据key参数获取该Map中对应的value,如果获取的value为null

* 则直接用传入的value覆盖原有的value,在这种情况下,可能要添加一组map对,

* 如果value不为null,则使用函数接口根据value,新value计算出一个新的结果,并用得到的结果去覆盖原有的value

*/

Integer merge = map.merge("123", 123123, (key,value) -> value+1000);

System.out.println(merge);//124123

System.out.println(map);//{123=124123}

}

}

Java8改进的HashMap和Hashtable实现类

Hashtable和HashMap区别

Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能高一点,但如果有多个线程访问同一个Map对象时,使用Hashtable实现类会更好、

Hashtable不允许使用null作为key和value,如果试图把null值放入Hashtable里,将引发空指针异常,但HashMap可是使用null作为key和value、

为了成功的在HashMap,Hashtable中存储,获取对象,用作key的对象必须实现hashCode方法和equals方法。

类似于HashSet,HashMap,Hashtable判断两个key相等的标准也是:两个key通过equals方法返回true,两个key的hashCode值也相等。

HashMap和Hashtable判断两个value相等的标准是:只要两个对象通过equals方法比较返回true即可。

public class ABHashtable {

public static void main(String[] args) {

Hashtable hashtable = new Hashtable<>();

hashtable.put(new A(123), "123");

hashtable.put(new A(1234), "1234");

hashtable.put(new A(1236), new B());

System.out.println(hashtable);

System.out.println(hashtable.containsValue("32342342"));//true

System.out.println(hashtable.containsKey(new A(123)));//true

System.out.println(hashtable.containsKey(new A(123123)));//false

}

}

上述代码解释:上述Hashtable中包含了B对象,而且重写了B对象的equals方法,它与任何对象通过equals都会返回true,所以在第一个输出是true。根据Hashtable判断两个key相等的标准,在第二个输出的时候,因为通过equals和hashCode都返回true,所以Hashtable判断这两个key相等,所以为true。

与HashSet类似的是,如果使用可变对象作为HashMap,Hashtable的key,如果程序修改了可变对象,那么程序再也无法准确访问到Map中被修改过的key。

public class ABHashtable2 {

public static void main(String[] args) {

HashMap hashtable = new HashMap();

hashtable.put(new A(123), "123");

hashtable.put(new A(1234), "1234");

//{mapTest.A@4d2=1234, mapTest.A@7b=123}

System.out.println(hashtable);

A next = (A) hashtable.keySet().iterator().next();

System.out.println(next.count);//1234

next.count = 123;

//{mapTest.A@7b=1234, mapTest.A@7b=123}

System.out.println(hashtable);

hashtable.remove(new A(123));

//只能删除没有被修改的key所对应的key-value对

System.out.println(hashtable);//{mapTest.A@7b=1234}

System.out.println(hashtable.get(new A(123)));//null

}

}

尽量不要使用可变对象作为key,如果确实需要,则尽量不要在程序中修改作为key的对象。

LinkedHashMap实现类

LinkedHashMap也使用双向链表来维护key-value对的次序,其实只需要考虑key的次序,该链表负责维护Map的迭代顺序,迭代顺序与key-value对的插入顺序保持一致。

因为他使用链表来维护内部顺序,所以在迭代访问Map里的全部元素时将有较好的性能,迭代输出LinkedHashMap的元素时,将会安添加key-value的顺序输出。

public class LinkedHashMapS {

public static void main(String[] args) {

LinkedHashMap map = new LinkedHashMap<>();

map.put("1", "1");

map.put("2", "2");

map.put("3", "3");

System.out.println(map);//{1=1, 2=2, 3=3}

}

}

使用Properties读写属性文件

Properties是Hashtable类的子类

Properties相当于一个key,value都是String的Map

public class PropertiesTest {

public static void main(String[] args) throws FileNotFoundException, IOException {

Properties properties = new Properties();

properties.setProperty("w","zq");

properties.setProperty("w1","zq1");

properties.setProperty("w2","zq2");

//输出文件目录,文件说明

properties.store(new FileOutputStream(new File("myProperties.properties")), "comment");

properties.storeToXML(new FileOutputStream(new File("myProperties1.xml")), "comment");

}

}

myProperties

#comment

#Fri Mar 09 10:11:42 CST 2018

w=zq

w1=zq1

w2=zq2

myProperties1

comment

zq

zq1

zq2

SortedMap接口和TreeMap实现类

TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。TreeMap也可以自然排序和定制排序。

TreeMap中判断两个key相等的标准是:两个key通过compareTo方法返回0,TreeMap即认为这两个key是相等的。

如果使用自定义类作为TreeMap的key,且想让TreeMap良好的工作,则重写该类的equals方法和compareTo方法时保持一致的返回结果。

Set和Map的关系十分密切,java源代码就是先实现了HashMap,TreeMMap等集合,然后通过包装一个所有的value都为null的Map集合实现了Set集合类。

public class TreeMapTest {

public static void main(String[] args) {

TreeMap treeMap = new TreeMap<>();

treeMap.put(12, 34);

treeMap.put(-12, 34);

treeMap.put(122, 34);

treeMap.put(0, 34);

//{-12=34, 0=34, 12=34, 122=34}

System.out.println(treeMap);

}

}

WeakHashMap实现类

WeakHashMap与HashMap的区别是:HashMap的key保留对实际对象的强引用,这意味着只要该HashMap对象不被销毁,该HashMap的所有key所引用的对象就不会被垃圾回收,HashMap也不会自动删除这些key所对应的key-value对;但WeakHashMap的key只保留了实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,WeakHashMap也可能自动删除这些key所对应的key-value对。

public class WeakHashMapTets {

public static void main(String[] args) {

WeakHashMap weakHashMap = new WeakHashMap<>();

weakHashMap.put(new String("1"), new String("1"));

weakHashMap.put(new String("2"), new String("2"));

weakHashMap.put(new String("3"), new String("3"));

weakHashMap.put("4", new String("4"));

//{4=4, 1=1, 2=2, 3=3}

System.out.println(weakHashMap);

System.gc();

System.runFinalization();

//{4=4}

System.out.println(weakHashMap);

//第四组key-value对的key是一个字符串直接量,系统会自动保留对该字符串对象的强引用,所以垃圾回收时不会回收他

}

}

如果需要使用WeakHashMap的key来保留对象的弱引用,则不要让该key所引用的对象具有任何强引用了否则将失去WeakHashMap的意义。

IdentityHashMap实现类

在IdentityHashMap中,当且仅当两个key严格相等key1 == key2时,IdentityHashMap才认为两个key相等,对于普通的HashMap而言,只要key1和key2通过equals方法比较返回true,且他们的hashCode值相等即可。

public class IdentityHashMapTest {

public static void main(String[] args) {

IdentityHashMap identityHashMap = new IdentityHashMap<>();

identityHashMap.put(new String("r"),"r");

identityHashMap.put(new String("r"),"r");

identityHashMap.put("java", 0);

identityHashMap.put("java", 1);

//{java=1, r=r, r=r}

System.out.println(identityHashMap);

/**

* 由于上面new String()的地址值不一样,IdentityHashCode返回值会不一样

* 所以第一个String与第二个String并不一样

* 但是java字符串直接量是一样的,所以第二次put就会覆盖原来的value

*/

}

}

EnumMap实现类

EnumMap中的所有key都必须是单个枚举类的枚举值,创建EnumMap时必须显示或隐式指定它对应的枚举类。

EnumMap具有如下特征

EnumMap在内部以数组形式保存,所以这种实现形式非常紧凑,高效。

EnumMap根据key的自然顺序,即枚举值的定义顺序,来维护key-value对的顺序。

EnumMap不允许使用null作为key,但允许使用null作为value,如果试图使用null作为key时将抛出空指针异常。如果只是查询是否包含值为null的key,或只是删除值为null的key,都不会抛出异常。

创建EnumMap时必须指定一个枚举类,从而将该EnumMap和指定的枚举类关联起来。

public class EnumMapTest {

public static void main(String[] args) {

EnumMap enumMap = new EnumMap(EnumMaps.class);

System.out.println(enumMap);//{}

enumMap.put(WINTER, "4");

enumMap.put(SPRING, "4");

enumMap.put(SUMMER, "4");

//{SPRING=4, SUMMER=4, WINTER=4}

System.out.println(enumMap);

}

}

各Map实现类的性能分析

HashMap和Hashtable的实现机制几乎一样,但由于Hashtable是一个古老的,线程安全的集合,因此HashMap通常比Hashtable要快。

TreeMap通常比HashMap,Hashtable要慢,尤其在插入删除key-value对时更慢,因为TreeMap底层采用红黑树来管理key-value对,红黑树的每个节点就是一个key-value对。

使用TreeMap有一个好处:TreeMap中的key-value对总是处于有序状态,无需专门进行排序操作。当TreeMap被填充之后,就可以调用keySet(),去的由key组成的Set,然后使用toArry()方法生成key的数组,接下来使用Arrays的binarySearch()方法在已排序的数组中快速地查询对象。

对于一般的应用场景,程序应该多考虑使用HashMap,因为HashMap正是为快速查询设计的:HashMap底层其实也是采用数组来存储key-value对。但如果程序需要一个总是排序好的Map时,则可以考虑使用TreeMap。

LinkedHashMap比HashMap慢一点,因为他需要维护链表来保持Map中key-value时的添加顺序。IdentityHashMap心梗没有特别出色之处,因为他采用与HashMap基本相似的实现,只是它使用==而不是equals方法来判断元素相等。EnumMap的性能最好,但它只能使用同一个枚举类的枚举值作为key。

HashSet和HashMap的性能选项

对于HashSet及其子类而言,它们采用hash算法来决定集合中元素的存储位置,并通过hash算法来控制集合的代销;对于HashMap,Hashtable及其子类而言,他们采用hash算法来决定Map中key的存储,并通过hash算法

设置不可变集合

public class NoModifyCollections {

//不可变对象都不可以增加和删除操作

public static void main(String[] args) {

//创建一个空的不可变的List对象

List emptyList = Collections.emptyList();

//创建一个还有一个元素,且不可改变的Set对象

Set singleton = Collections.singleton("java");

HashMap map = new HashMap<>();

map.put("", "");

//返回普通Map对象对应的不可变版本

Map map2 = Collections.unmodifiableMap(map);

}

}

Java9 增加的不可变集合

public class NoModifyCollections9 {

public static void main(String[] args) {

List of = List.of("");

Set of2 = Set.of("");

Map of3 = Map.of("1","2","3","4");

System.out.println(of3);//{3=4, 1=2}

Map ofEntries = Map.ofEntries(Map.entry("", ""));

System.out.println(ofEntries);//{=}

}

}

繁琐的接口Enumeration

繁琐的接口Enumeration:只能遍历Vector和Hashtable这种老java类

public class EnumerationTeST {

public static void main(String[] args) {

Vector vector = new Vector();

vector.add("3");

vector.add("2");

vector.add("1");

Enumeration elements = vector.elements();

while (elements.hasMoreElements()) {

System.out.println(elements.nextElement()); // 3 2 1

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值