如果我猜得没错的话,您想要一个通用方法,接收一对原始类型数组,并返回一个特定的映射,其键和值与数组相匹配。
此外,您还想要另一个方法,接收一个映射并返回一对原始类型数组,其元素与映射条目相匹配。
如果这些假设是正确的,那么您可以尝试像这样“装箱”您的原始类型:
public static Integer[] box(int[] primitives) {
return IntStream.of(primitives).boxed().toArray(Integer[]::new);
}
public static Byte[] box(byte[] primitives) {
return IntStream.range(0, primitives.length).mapToObj(
i -> primitives[i]).toArray(Byte[]::new);
}
public static Double[] box(double[] primitives) {
return DoubleStream.of(primitives).boxed().toArray(Double[]::new);
}
public static Float[] box(float[] primitives) {
return IntStream.range(0, primitives.length).mapToObj(
i -> primitives[i]).toArray(Float[]::new);
}
public static Long[] box(long[] primitives) {
return LongStream.of(primitives).boxed().toArray(Long[]::new);
}
然后,您可以按以下方式实现通用的
toMap()
方法:
public static <K, V, M extends Map<K, V>> M toMap(
K[] keys,
V[] values,
Supplier<M> factory) {
return IntStream.range(0, keys.length).boxed().collect(
Collectors.toMap(i -> keys[i], i -> values[i], (a, b) -> a, factory));
}
这个函数通过迭代keys和values数组,将每对元素放在factory参数提供的map上,从而将流收集到一个map中。这个factory实际上是一个Supplier,它将被用来创建具体的map实现,比如HashMap、TreeMap、LinkedHashMap等。
请注意,如果map实现不保留插入顺序,比如HashMap,那么您可能会失去元素的顺序。
要进行反向操作,您需要一个辅助类来保存两个数组:
public class Pair<A, B> {
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
public final A a;
public final B b;
}
这是一个简单的键值对容器。然后,您可以按照以下方式将给定的映射转换为一对数组:
public static <K, V, M extends Map<K, V>> Pair<K[], V[]> toArrays(
M map,
IntFunction<K[]> keysFactory,
IntFunction<V[]> valuesFactory) {
K[] keys = map.keySet().stream().toArray(keysFactory);
V[] values = map.values().stream().toArray(valuesFactory);
return new Pair<>(keys, values);
}
这将通过在给定地图的keySet()和values()集合上进行流处理来创建keys和values数组。分别提供了扮演工厂角色的IntFunction,以使泛型机制按预期工作。否则,您将无法将数组元素的通用类型修复为映射的键和值的通用类型。
在Pair类中,您无法持有原始数组,因为它是通用的,并且(截至2015年9月)仍不允许使用原始类型作为类型参数。
因此,我们需要几个取消装箱方法:
public static int[] unbox(Integer[] wrappers) {
return Arrays.stream(wrappers).mapToInt(Integer::intValue).toArray();
}
public static float[] unbox(Float[] wrappers) {
float[] result = new float[wrappers.length];
IntStream.range(0, wrappers.length).forEachOrdered(
i -> result[i] = wrappers[i].floatValue());
return result;
}
最后,这里有一个示例展示了如何使用这段代码:
String[] keys = { "one", "two", "three" };
int[] intValues = { 1, 2, 3 };
float[] floatValues = { 1.1f, 2.2f, 3.3f };
Integer[] integers = box(intValues);
Map<String, Integer> map = toMap(keys, integers, HashMap::new);
System.out.println(map);
Float[] floats = box(floatValues);
Map<String, Float> map2 = toMap(keys, floats, LinkedHashMap::new);
System.out.println(map2);
Pair<String[], Integer[]> arrays = toArrays(map, String[]::new, Integer[]::new);
System.out.println(Arrays.toString(arrays.a));
int[] unboxedInts = unbox(arrays.b);
System.out.println(Arrays.toString(unboxedInts));
Pair<String[], Float[]> arrays2 = toArrays(map2, String[]::new, Float[]::new);
System.out.println(Arrays.toString(arrays2.a));
float[] unboxedFloats = unbox(arrays2.b);
System.out.println(Arrays.toString(unboxedFloats));
在Java中,浮点数、布尔值、短整型、字符和字节均没有流可用,因此您需要使用一些解决方法。
泛型语法并不是很清晰,但它允许您修复泛型类型,就像我对Map的键和值所做的那样。
最后注意:HashMap不保留插入顺序,而LinkedHashMap则会保留。这解释了map和map2输出之间的差异。