Convert int[] to Integer[] in Java and Back to int[]

Convert int[] to Integer[] in Java with boxed() and back with mapToInt(), handle null elements, long, double and char arrays, and use ArrayUtils.

An int array stores values next to each other, an Integer array stores references to Integer objects

Java has no cast between int[] and Integer[], so to convert int[] to Integer[] we box every element into a new array, most often with Arrays.stream(ints).boxed().toArray(Integer[]::new), and to go back we unbox every element with mapToInt(Integer::intValue).toArray(). Both directions create a new array and leave the original unchanged.

We need an Integer[] when an API works only with objects, for example Arrays.sort() with a Comparator or a generic method that takes T[]. We go back to int[] for arithmetic and for compact storage of large numeric data.

The following example converts an array of game scores in both directions.

int[] scores = {70, 85, 90};
Integer[] boxed = Arrays.stream(scores).boxed().toArray(Integer[]::new);    // [70, 85, 90]
int[] unboxed = Arrays.stream(boxed).mapToInt(Integer::intValue).toArray();  // [70, 85, 90]

Notice the Integer[]::new argument, because without it toArray() returns an Object[]. We start with the reason a cast fails and cover loops, null elements in an Integer[], the other primitive types and Apache Commons Lang, and we finish with a sorting use case and a comparison table.

1. Why int[] Cannot Be Cast to Integer[]

Autoboxing, the boxing conversion of the JLS, converts one int value into one Integer object. It never applies to a whole array, because int[] and Integer[] are unrelated types with a different memory layout.

An int array stores values next to each other, an Integer array stores references to Integer objects
An int[] holds the values themselves, whereas an Integer[] holds references to separate Integer objects

An int[] stores the numbers next to each other. An Integer[] stores references, and each reference points to a separate Integer object on the heap, which is also why an Integer[] takes several times more memory. The compiler rejects a cast in either direction.

// does not compile: incompatible types, int[] cannot be converted to Integer[]
int[] scores = {70, 85, 90};
Integer[] boxed = (Integer[]) scores;

So every conversion visits each element once and copies it into a new array. The approaches in this article differ only in how much code we write for that loop.

2. Convert int[] to Integer[] by Boxing

The IntStream.boxed() method turns each int into an Integer, and toArray() collects the results. The generator argument decides the array type, and leaving it out is a common mistake.

int[] scores = {70, 85, 90};
Integer[] boxed = IntStream.of(scores).boxed().toArray(Integer[]::new);   // [70, 85, 90]
Object[] objects = IntStream.of(scores).boxed().toArray();               // [70, 85, 90], but typed Object[]

The no-argument toArray() returns an Object[], and casting that result to Integer[] throws ClassCastException at runtime. Passing Integer[]::new creates an array of the right type from the start.

Without streams, a loop or Arrays.setAll() does the same job. Both fill a pre-sized array, and each assignment autoboxes one value.

int[] scores = {70, 85, 90};
Integer[] viaLoop = new Integer[scores.length];
for (int i = 0; i < scores.length; i++) {
    viaLoop[i] = scores[i];
}
Integer[] viaSetAll = new Integer[scores.length];
Arrays.setAll(viaSetAll, i -> scores[i]);
String result = Arrays.toString(viaSetAll);   // "[70, 85, 90]"

The loop creates no stream objects, which can matter for very large arrays in hot code, whereas the stream version reads better everywhere else. Boxing goes through Integer.valueOf(), which caches the values from -128 to 127, so small numbers reuse the same objects.

3. Unboxing Integer[] into int[]

The reverse direction maps each Integer to its int value with mapToInt(), which returns an IntStream, and toArray() on an IntStream returns an int[] with no generator needed.

Integer[] ratings = {4, 5, 3};
int[] values = Arrays.stream(ratings).mapToInt(Integer::intValue).toArray();   // [4, 5, 3]

An Integer[] can contain null, and unboxing a null element throws NullPointerException, so we decide up front what a missing value means. For example, a survey app stores an Integer[] of ratings in which null means the user skipped the question.

Integer[] ratings = {4, null, 3};
int[] crash = Arrays.stream(ratings).mapToInt(Integer::intValue).toArray();          // NullPointerException
int[] withZero = Arrays.stream(ratings).mapToInt(r -> r == null ? 0 : r).toArray();  // [4, 0, 3]
int[] answered = Arrays.stream(ratings).filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();   // [4, 3]

Replacing null with 0 keeps the positions, so index 1 still belongs to the second question. Filtering keeps only real answers, which is the right choice for an average, because a 0 would pull the average down.

4. long, double and char Arrays

The same two patterns work for long and double, because Java has LongStream and DoubleStream next to IntStream. The other primitive types have no stream, so they need a loop.

Primitive arrayTo wrapper arrayBack to primitive array
long[]Arrays.stream(a).boxed().toArray(Long[]::new)Arrays.stream(b).mapToLong(Long::longValue).toArray()
double[]Arrays.stream(a).boxed().toArray(Double[]::new)Arrays.stream(b).mapToDouble(Double::doubleValue).toArray()
char[], boolean[], byte[], short[], float[]Loop, or ArrayUtils.toObject()Loop, or ArrayUtils.toPrimitive()

For a char[], we can also go through String.chars(), which returns the characters as an IntStream, and cast each value back to char before boxing.

long[] sizes = {2048L, 512L};
Long[] boxedSizes = Arrays.stream(sizes).boxed().toArray(Long[]::new);   // [2048, 512]
char[] grades = {'A', 'B'};
Character[] boxedGrades = new String(grades).chars().mapToObj(c -> (char) c).toArray(Character[]::new);   // [A, B]

5. ArrayUtils.toObject() and toPrimitive() from Commons Lang

If the project already uses Apache Commons Lang, its ArrayUtils class does both conversions in one call and has overloads for all eight primitive types. We add the current commons-lang3 version.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.21.0</version>
</dependency>

The toPrimitive() method has a second overload with a default value for null elements, which saves us the ternary from section 3. Both methods return null for a null array instead of throwing.

int[] scores = {70, 85, 90};
Integer[] boxed = ArrayUtils.toObject(scores);           // [70, 85, 90]
Integer[] ratings = {4, null, 3};
int[] safe = ArrayUtils.toPrimitive(ratings, 0);         // [4, 0, 3]
int[] strict = ArrayUtils.toPrimitive(ratings);          // NullPointerException
int[] none = ArrayUtils.toPrimitive((Integer[]) null);   // null

Internally, ArrayUtils runs the same loop as section 2, so it is not faster. It is worth adding only for the shorter code, not for a single conversion in a project without the library.

6. Sorting a Leaderboard in Descending Order

A leaderboard shows the highest scores first. The scores arrive as an int[] from the game engine, but Arrays.sort(int[]) sorts only in ascending order, and the overload that takes a Comparator exists only for object arrays.

int[] scores = {70, 95, 85, 60};
Integer[] boxed = Arrays.stream(scores).boxed().toArray(Integer[]::new);
Arrays.sort(boxed, Comparator.reverseOrder());
int[] ranked = Arrays.stream(boxed).mapToInt(Integer::intValue).toArray();   // [95, 85, 70, 60]

We box, sort with Comparator.reverseOrder() and unbox again. For a large array, sorting the int[] ascending and reversing the array in place avoids the boxing, so it is faster and uses less memory.

7. Streams, Loops or ArrayUtils

All the methods take O(n) time and create a new array, so the choice comes down to the Java version, the element type and how null elements must be handled.

MethodDirectionTypesnull elementsDependency
boxed().toArray(Integer[]::new)int[] to Integer[]int, long, doubleNot possible in int[]None
mapToInt(Integer::intValue).toArray()Integer[] to int[]int, long, doubleNullPointerException unless mapped or filteredNone
Loop or Arrays.setAll()BothAll eightHandled in our own codeNone
ArrayUtils.toObject() and toPrimitive()BothAll eightDefault value with the two-argument toPrimitive()commons-lang3

When the target is a collection instead of an array, we skip the wrapper array and convert the primitive array to a List with boxed().toList().

8. int[] and Integer[] Conversion FAQs

Casting, type erasure, null values and lists come up once the first conversion compiles.

8.1. Can we cast an int[] to an Integer[] in Java?

No. The two types are unrelated array types, so a cast does not compile. Autoboxing works only for single values, as section 1 shows, so we copy the elements into a new array.

8.2. Why does toArray() return Object[] instead of Integer[]?

Because of type erasure, a Stream<Integer> does not know its element type at runtime. The toArray(IntFunction) overload takes a generator such as Integer[]::new and creates an array of the type we pass.

8.3. How do we convert an Integer[] with null values to int[]?

We either map each null to a default with mapToInt(r -> r == null ? 0 : r), or drop it with filter(Objects::nonNull). With Commons Lang, ArrayUtils.toPrimitive(array, 0) does the mapping for us.

8.4. Does changing the Integer[] change the original int[]?

No. Every method in this article creates a new array with copies of the values, so the two arrays are independent after the conversion.

8.5. How do we convert an int[] to a List<Integer>?

We call IntStream.of(array).boxed().toList(). For more options, including the mutable versions, see the article on converting between a List and an array.

9. Conclusion

An int[] and an Integer[] cannot be cast to each other, so each conversion copies the elements into a new array. The stream versions are one line in each direction, boxed().toArray(Integer[]::new) and mapToInt(Integer::intValue).toArray().

The main trap is null, which an Integer[] allows and an int[] does not, so we map or filter it before unboxing. For char, boolean and the other small types, a loop or ArrayUtils covers what the streams do not.

10. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.