将对象数组转换为其基元类型的数组

如果您有一个 Java 对象数组,它具有基元类型(例如 Byte、 Integer、 Char 等)。有没有一种简单的方法可以把它转换成一个基元类型的数组?特别是可以在不必创建新数组和循环遍历内容的情况下实现这一点。

举个例子

Integer[] array

什么是最简单的方法把它转换成

int[] intArray

不幸的是,在 Hibernate 和一些我们无法控制的第三方库之间进行接口时,我们必须经常这样做。这似乎是一个相当普遍的操作,所以我会感到惊讶,如果没有捷径。

谢谢你的帮助!

54592 次浏览

Unfortunately, there's nothing in the Java platform that does this. Btw, you also need to explicitly handle null elements in the Integer[] array (what int are you going to use for those?).

特别是可以在不必创建新数组和循环遍历内容的情况下实现这一点。

在 Java 中,不能将 Integer 数组转换为 int (即不能更改数组元素的类型)。因此,您要么必须创建一个新的 int []数组并将 Integer 对象的值复制到其中,要么可以使用适配器:

class IntAdapter {
private Integer[] array;
public IntAdapter (Integer[] array) { this.array = array; }
public int get (int index) { return array[index].intValue(); }
}

这可以使代码更具可读性,并且 IntAdapter 对象只占用几个字节的内存。适配器的最大优点是您可以在这里处理特殊情况:

class IntAdapter {
private Integer[] array;
public int nullValue = 0;
public IntAdapter (Integer[] array) { this.array = array; }
public int get (int index) {
return array[index] == null ? nullValue : array[index].intValue();
}
}

另一个解决方案是使用包含大量预定义适配器的 Commons Primities

如果你只做一次,那就用简单的方法。但是你还没有谈到 Integer!= 空格。

    //array is the Integer array
int[] array2 = new int[array.length];
int i=0;
for (Integer integer : array) {
array2[i] = integer.intValue();
i++;
}

再一次,Apache Commons Lang是你的朋友。他们提供的 ArrayUtils.toPrimitive ()正是你所需要的。您可以指定如何处理空值。

使用 一美元简单如下:

Integer[] array = ...;
int[] primitiveArray = $(array).toIntArray();

使用 番石榴:

int[] intArray = Ints.toArray(Arrays.asList(array));

文件:

通过在 Java8中引入 溪流,可以做到这一点:

int[] intArray = Arrays.stream(array).mapToInt(Integer::intValue).toArray();

但是,目前只有 intlongdouble的基本流。如果您需要转换到另一个基本类型,如 byte,没有外部库的最短方法是:

byte[] byteArray = new byte[array.length];
for(int i = 0; i < array.length; i++) byteArray[i] = array[i];

或者,如果需要,for 循环可以替换为流:

IntStream.range(0, array.length).forEach(i -> byteArray[i] = array[i]);

如果您的任何元素是 null,所有这些都将抛出 NullPointerException

下面是所有基元类型的通用解决方案

/**
* Convert Collection to equivalent array of primitive type
* @param <S> [in] Object type of source collection
* @param tcls [in] class of the primitive element
* @param q [in] source collection
* @return Equivalent Array of tcls-elements, requires cast to "tcls"[]
*/
public static <S> Object asPrimitiveArray(Class<?> tcls, Collection<S> q)
{
int n = q.size();
Object res = Array.newInstance(tcls, n);
Iterator<S> i = q.iterator();
int j = 0;
while (i.hasNext())
{
Array.set(res, j++, i.next());
}
return res;
}


/**
* Convert Object array to equivalent array of primitive type
* @param <S> [in] Object type of source array
* @param tcls [in] class of the primitive element
* @param s [in] source array
* @return Equivalent Array of tcls-elements, requires cast to "tcls"[]
*/
public static <S> Object asPrimitiveArray(Class<?> tcls, S[] s)
{
return asPrimitiveArray(tcls, Arrays.asList(s));
}

用于整数到整数的转换

Integer[] a = ...
int[] t = (int[]) asPrimitiveArray(int.class, a);

我们可以使用 Stream API 从它们的对应的装箱对象创建基元类型数组。

对于 Character[]阵列转换为 char[],使用相应大小分配的定制 Collector,与 Supplier<CharBuffer>BiConsumer<CharBuffer, Character>累加器,BinaryOperator<CharBuffer>合并器和 Function<CharBuffer, char[]>完成器) ,如下将工作:

Collector<Character, CharBuffer, char[]> charArrayCollector = Collector.of(
() -> CharBuffer.allocate(95),
CharBuffer::put,
CharBuffer::put,
CharBuffer::array
);

它为可打印的 ASCII 字符提供 CharBuffer,将每个流字符累积到一个 CharBuffer 实例中,将来自多个 CharBuffer 实例的并行处理结果按照正确的顺序组合在一起,最终在所有线程完成后,根据累积和组合的结果构建所需的 char[]数组。

首先,我们从标准的可打印的 ASCII 集合中创建一个 Character[]测试数组,利用来自 IntStreamint值,迭代 ASCII 范围并将每个值映射到字符 Stream,然后将它们转换为 char原语并将其转换为 Character对象:

Character[] asciiCharacters = IntStream.range(32, 127)
.mapToObj(i -> Character.valueOf((char)i))
.toArray(Character[]::new);

现在,我们只需要从 Character数组创建一个字符的 Stream,然后可以通过自定义 Collector 将其收集到 char[]数组中。

char[] asciiChars = Stream.of(asciiCharacters ).collect(charArrayCollector);

相应地,这适用于其他 Number类型:

byte[] bytes = new byte[] { Byte.MIN_VALUE, -1 , 0, 1, Byte.MAX_VALUE };
Byte[] boxedBytes = IntStream.range(0, bytes.length)
.mapToObj(i -> bytes[i])
.toArray(Byte[]::new);
byte[] collectedBytes = Stream.of(boxedBytes).collect(
Collector.of(
() -> ByteBuffer.allocate(boxedBytes.length),
ByteBuffer::put,
ByteBuffer::put,
ByteBuffer::array
)
);


short[] shorts = new short[] { Short.MIN_VALUE, -1, 0, 1, Short.MAX_VALUE };
Short[] boxedShorts = IntStream.range(0, shorts.length)
.mapToObj(i -> shorts[i])
.toArray(Short[]::new);
short[] collectedShorts = Stream.of(boxedShorts).collect(
Collector.of(
() -> ShortBuffer.allocate(boxedShorts .length),
ShortBuffer::put,
ShortBuffer::put,
ShortBuffer::array
)
);


float[] floats = new float[] { Float.MIN_VALUE, -1.0f, 0f, 1.0f, Float.MAX_VALUE };
Float[] boxedFLoats = IntStream.range(0, floats.length)
.mapToObj(i -> floats[i])
.toArray(Float[]::new);
float[] collectedFloats = Stream.of(boxedFLoats).collect(
Collector.of(
() -> FloatBuffer.allocate(boxedFLoats.length),
FloatBuffer::put,
FloatBuffer::put,
FloatBuffer::array
)
);

Stream API 支持的基元类型可以更容易地转换:

int[] ints = new int[] { Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE };
Integer[] integers = IntStream.of(ints).boxed().toArray(Integer[]::new);
int[] collectedInts = Stream.of(integers).collect(
Collector.of(
() -> IntBuffer.allocate(integers.length),
IntBuffer::put,
IntBuffer::put,
IntBuffer::array
)
);


long[] longs = new long[] { Long.MIN_VALUE, -1l, 0l, 1l, Long.MAX_VALUE };
Long[] boxedLongs = LongStream.of(longs).boxed().toArray(Long[]::new);
long[] collectedLongs = Stream.of(boxedLongs ).collect(
Collector.of(
() -> LongBuffer.allocate(boxedLongs .length),
LongBuffer::put,
LongBuffer::put,
LongBuffer::array
)
);


double[] doubles = new double[] { Double.MIN_VALUE, -1.0, 0, 1.0, Double.MAX_VALUE };
Double[] boxedDoubles = DoubleStream.of(doubles)
.boxed()
.toArray(Double[]::new);
double[] collectedDoubles = Stream.of(boxedDoubles).collect(
Collector.of(
() -> DoubleBuffer.allocate(boxedDoubles.length),
DoubleBuffer::put,
DoubleBuffer::put,
DoubleBuffer::array
)
);