Arrays & Multidimensional Arrays

15 questions found

A sparse matrix stores only the non-default (non-zero) elements, commonly using a Map<Long, T> keyed by an encoded (row, column) pair, or a Map<Integer, Map<Integer, T>> for nested row-then-column lookup, or specialized formats like Compressed Sparse Row (CSR) for numerical computing -- this avoids allocating and holding memory for the potentially enormous number of default-valued cells a genuinely sparse dataset (like a large graph's adjacency matrix, or a mostly-empty spreadsheet) would otherwise require if represented as a dense 2D array.
public class SparseMatrix {
    private final Map<Long, Double> data = new HashMap<>();
    private final int cols;
    public SparseMatrix(int cols) { this.cols = cols; }

    private long key(int row, int col) { return (long) row * cols + col; }

    public void set(int row, int col, double value) {
        if (value == 0.0) data.remove(key(row, col));
        else data.put(key(row, col), value);
    }

    public double get(int row, int col) {
        return data.getOrDefault(key(row, col), 0.0);
    }
}
Real-world example A recommendation engine's user-item interaction matrix (millions of users by millions of items, but each user has only interacted with a tiny fraction) is stored as a sparse Map-based structure rather than a dense 2D array, since a dense representation at that scale would require far more memory than any reasonable server could provide.

Common follow-ups: What's the performance trade-off of Map-based sparse storage versus a dense array for operations like matrix multiplication?;How do specialized sparse matrix libraries (like those used in scientific computing) further optimize beyond a simple HashMap-based approach?

Collections Framework;Diagnostics & Performance
Due to Java's type erasure, generic type information isn't available at runtime, so the JVM couldn't correctly enforce the component type of a genuinely generic array at the point of array creation -- combined with array covariance's already-demonstrated unsoundness (ArrayStoreException), allowing new T[] or new List<String>[] directly would create even more severe, undetectable type-safety holes, so Java simply disallows this syntax entirely at compile time, requiring workarounds like creating an Object[] and unsafely casting, or preferring a generic-friendly collection like ArrayList<T> instead.
public class Container<T> {
    // private T[] items = new T[10];  // COMPILE ERROR: generic array creation

    @SuppressWarnings("unchecked")
    private T[] items = (T[]) new Object[10];  // common workaround, but unsafe and generates a warning

    // Preferred alternative: just use a List instead
    private List<T> betterItems = new ArrayList<>();
}
Real-world example A generic container class initially attempts private T[] items = new T[10] and hits a compile error, leading the team to either use the unsafe Object[]-cast workaround (accepting the unchecked warning) or, preferably, refactor to use ArrayList<T> internally instead, sidestepping the entire generic array limitation.

Common follow-ups: Why does the unsafe (T[]) cast workaround still risk a ClassCastException later, and under what circumstances?;How does the JDK's own source code (like ArrayList's internal implementation) handle this exact limitation internally?

Generics;Collections Framework
An array of primitives (int[], double[]) has elements automatically initialized to their type's zero-equivalent default (0, 0.0, false), while an array of reference types (String[], custom objects) has every element initialized to null by default, since no object instance is automatically created -- attempting to call a method on an uninitialized reference-type array element before explicitly assigning it throws a NullPointerException.
int[] nums = new int[3];        // {0, 0, 0}
boolean[] flags = new boolean[3];  // {false, false, false}
String[] names = new String[3];    // {null, null, null}

System.out.println(names[0].length());  // throws NullPointerException, since names[0] is null
Real-world example A beginner's attempt to call .length() on an element of a freshly created String[] array (without first assigning actual String values to each slot) throws a NullPointerException, a common early mistake stemming from not realizing reference-type arrays default to null rather than empty strings.

Common follow-ups: Why don't reference-type arrays default to an empty object instance instead of null?;How would you safely initialize every element of an object array to a non-null default value?

Java Fundamentals: Syntax Data Types & Operators;Exceptions
Flattening a 2D array involves iterating each row and copying its elements sequentially into a pre-sized 1D destination array (tracking a running offset via System.arraycopy() for efficiency); reshaping a 1D array into 2D requires knowing the desired row/column dimensions in advance and copying corresponding slices of the source array into each newly allocated row -- neither operation has a single built-in JDK utility method, so both are typically implemented manually using System.arraycopy() for performance.
public static int[] flatten(int[][] matrix) {
    int totalLength = Arrays.stream(matrix).mapToInt(row -> row.length).sum();
    int[] result = new int[totalLength];
    int offset = 0;
    for (int[] row : matrix) {
        System.arraycopy(row, 0, result, offset, row.length);
        offset += row.length;
    }
    return result;
}
Real-world example An image-processing routine flattens a 2D pixel grid into a single contiguous 1D array before passing it to a native image-encoding library expecting flat pixel data, using System.arraycopy() per row for efficient bulk copying rather than a slower element-by-element nested loop.

Common follow-ups: What is the time complexity of the flattening operation relative to the total number of elements?;How would you handle flattening a jagged (non-rectangular) 2D array where rows have different lengths?

Diagnostics & Performance;Collections Framework
A Java array is itself an object on the heap, carrying an object header (typically 12-16 bytes on a 64-bit JVM, including a mark word and class pointer) plus a 4-byte length field, followed by the actual element data laid out contiguously -- a primitive array (like int[]) stores raw values directly and compactly in this contiguous block, while an array of boxed wrapper types (Integer[]) instead stores references (pointers) to separately-heap-allocated Integer objects, meaning each element incurs both the pointer's own 4-8 bytes AND a separate object header for each boxed Integer instance, resulting in dramatically higher memory usage and worse cache locality for large numeric datasets.
// Primitive array: compact, contiguous memory, ~16 bytes header + 4 bytes per int
int[] primitiveArray = new int[1_000_000];  // roughly 4MB total

// Boxed array: each element is a separate heap object plus a reference
Integer[] boxedArray = new Integer[1_000_000];  // roughly 20MB+ total (references + individual Integer objects)
Real-world example A scientific computing application processing millions of numeric data points switches from using an Integer[] (or a generic List<Integer>) to a raw int[] array after profiling revealed the boxed representation was consuming roughly 4-5x more heap memory and causing significantly worse CPU cache performance due to pointer-chasing through scattered Integer objects.

Common follow-ups: How does the JIT compiler's escape analysis sometimes mitigate boxing overhead in tight loops?;What is the memory layout difference between a 2D primitive array and a flattened 1D equivalent?

Garbage Collection;Diagnostics & Performance

Showing 11–15 of 15