在 Java 中用一行代码来声明和初始化 map

Map 是我们常用到的一个容器,我们会用 map 来保存一些后续需要查找的数据, 今天我们来看一下,在 Java 中如何使用一行代码来初始化 map。

环境

  • JDK: 1.8

问题

一般我们初始化 map 是这样:

Map<String, Runnable> map = new HashMap<>();
map.put("a", new Runnable() {
	@Override
	void run() {
		logger.info("running a");
	}
});
map.put("b", new Runnable() {
	@Override
	void run() {
		logger.info("running b");
	}
});

这样一个 map 就初始化完成了,不过如果这个 map 是某个类的成员变量, 如果想要在定义时就执行初始化,那么我们可能会需要创建一个函数:

class A {
	Map<String, Runnable> createMap() {
		Map<String, Runnable> map = new HashMap<>();
		map.put("a", new Runnable() {
			@Override
			void run() {
				logger.info("running a");
			}
		});
		map.put("b", new Runnable() {
			@Override
			void run() {
				logger.info("running b");
			}
		});
		return map;
	}
	Map<String, Runnable> map = createMap();
}

这么做似乎有点啰嗦,那么有没有一种办法一次性同时完成定义和初始化呢?

解决

1. Arrays

我们可以利用 Arrays.asList 方法,先创建一个 List<Entry> 然后转成 Stream , 接下来 collect 成 map,拆解步骤是这样:

import java.util.Arrays;
import java.util.AbstractMap.SimpleEntry;

List<SimpleEntry> list = Arrays.asList(
	new SimpleEntry<>("a", new Runnable() {
		@Override
		void run() {
			logger.info("running a");
		}
	}),
	new SimpleEntry<>("b", new Runnable() {
		@Override
		void run() {
			logger.info("running b");
		}
	})
);

Map<String, Runnable> map = list.stream().collect(Collectors.toMap(
	d -> d.getKey(), d -> d.getValue()
));

合并为一步会变成这样:

Map<String, Runnable> map = Arrays.asList(
	new SimpleEntry<>("a", new Runnable() {
		@Override
		void run() {
			logger.info("running a");
		}
	}),
	new SimpleEntry<>("b", new Runnable() {
		@Override
		void run() {
			logger.info("running b");
		}
	})
).stream().collect(Collectors.toMap(
	d -> d.getKey(), d -> d.getValue()
));

这样我们就完成了一步同时完成定义和初始化。

2. Stream

如果我们更熟悉 Stream,这个方法还可以进一步简化, 我们可以完全把创建 List 的这个步骤去掉,直接从 Stream 开始:

import java.util.stream.Stream;

Map<String, Runnable> map = Stream.of(
	new SimpleEntry<>("a", new Runnable() {
		@Override
		void run() {
			logger.info("running a");
		}
	}),
	new SimpleEntry<>("b", new Runnable() {
		@Override
		void run() {
			logger.info("running b");
		}
	})
).collect(Collectors.toMap(
	d -> d.getKey(), d -> d.getValue()
));

总结

很多人都觉得 java 是一门比较啰嗦的语言,所以我会尽量去简化一些写法, 当然写法的问题有时候见仁见智,可能也会有读者觉得这样写会不太清晰, 调试起来也比较复杂,我是觉得清晰的话,熟悉 stream 其实还好, 调试的话确实有些不便,但是其实我们不太需要调试 map 的初始化过程, 当然肯定会有例外,这个写法最大的问题,我想可能是实际写的时候, 如果代码中有语法或是依赖问题,就很难去寻找到底是哪部分代码出了问题, 这时一般我会采用分离的方式把代码写出来,看看问题在哪里,然后再改回去。 总体而言,这个也还是目前我比较满意的初始化 map 的方法。