杰瑞科技汇

Java ArrayList如何高效存储byte类型数据?

Of course! This is a very common and important topic in Java. Let's break down how to use an ArrayList for byte values, covering the standard approach, the recommended approach, and why they differ.

Java ArrayList如何高效存储byte类型数据?-图1
(图片来源网络,侵删)

The Core Problem: No ArrayList<byte>

First, a key point in Java's type system: primitive types (like byte, int, double, etc.) cannot be used as type parameters for generic classes like ArrayList.

This means the following code will not compile:

// THIS WILL CAUSE A COMPILE ERROR
ArrayList<byte> byteList = new ArrayList<byte>(); 

The Java compiler enforces this because generics are designed to work with object references, not primitive values stored directly on the stack.


Solution 1: The Wrapper Class Byte (The Standard, but Less Efficient Way)

The classic solution is to use the corresponding wrapper class for the primitive type. For byte, the wrapper class is java.lang.Byte.

Java ArrayList如何高效存储byte类型数据?-图2
(图片来源网络,侵删)

Since Byte is a class (it's an object), it can be used as a type parameter for an ArrayList.

How to Use ArrayList<Byte>

You create the list using Byte, but you can still add primitive byte values directly due to a feature called autoboxing.

Example:

import java.util.ArrayList;
import java.util.List;
public class ByteArrayListExample {
    public static void main(String[] args) {
        // Create an ArrayList that stores Byte objects
        List<Byte> byteList = new ArrayList<>();
        // ADDING ELEMENTS (Autoboxing happens here)
        // The Java compiler automatically converts the primitive byte '10' to a Byte object.
        byteList.add((byte) 10);   // Best practice to cast to be explicit
        byteList.add((byte) 20);
        byteList.add((byte) 30);
        // You can also add Byte objects directly
        Byte b = (byte) 40;
        byteList.add(b);
        System.out.println("Initial list: " + byteList); // [10, 20, 30, 40]
        // ACCESSING ELEMENTS (Unboxing happens here)
        // The compiler automatically converts the Byte object back to a primitive byte.
        byte firstByte = byteList.get(0);
        System.out.println("First element: " + firstByte); // 10
        // MODIFYING AN ELEMENT
        byteList.set(1, (byte) 25);
        System.out.println("List after modification: " + byteList); // [10, 25, 30, 40]
        // REMOVING AN ELEMENT
        byteList.remove(2); // Removes the element at index 2 (which is 30)
        System.out.println("List after removal: " + byteList); // [10, 25, 40]
        // ITERATING
        System.out.println("\nIterating through the list:");
        for (Byte currentByte : byteList) {
            // In this loop, 'currentByte' is a Byte object.
            // We call a method on it.
            System.out.println("Current byte value: " + currentByte);
        }
        // Important: To get the primitive value, you must call .byteValue()
        // This is called unboxing.
        byte primitiveValue = byteList.get(0).byteValue();
        System.out.println("\nPrimitive value from list: " + primitiveValue);
    }
}

Disadvantages of ArrayList<Byte>

While this works, it has a significant performance and memory overhead:

Java ArrayList如何高效存储byte类型数据?-图3
(图片来源网络,侵删)
  1. Memory Overhead: Each Byte object has a non-trivial memory footprint (e.g., 16 bytes on a 64-bit JVM for an empty object, plus 1 byte for the actual byte value). For a list of 1000 bytes, you are creating 1000 objects, consuming much more memory than the 1000 bytes themselves.
  2. Performance Overhead: Autoboxing and unboxing add extra CPU cycles. Every time you add a byte, the JVM must create a Byte object. Every time you get a value, it must unwrap it from the object. This can be slow in performance-critical code (e.g., game development, financial trading, large data processing).

Solution 2: The Modern, Recommended Approach: byte[]

If your primary goal is to store a sequence of byte values efficiently and you don't need the dynamic resizing or rich API of an ArrayList, the best choice is a simple array: byte[].

This is the most memory-efficient and fastest way to handle a collection of bytes in Java.

Example:

public class ByteArrayExample {
    public static void main(String[] args) {
        // Create an array of bytes with a fixed initial size
        byte[] byteArray = new byte[5];
        // ADDING/SETTING ELEMENTS
        byteArray[0] = 10;
        byteArray[1] = 20;
        byteArray[2] = 30;
        byteArray[3] = 40;
        byteArray[4] = 50;
        System.out.println("Array length: " + byteArray.length); // 5
        // ACCESSING ELEMENTS
        byte firstByte = byteArray[0];
        System.out.println("First element: " + firstByte); // 10
        // MODIFYING AN ELEMENT
        byteArray[1] = 25;
        System.out.println("Array after modification: " + java.util.Arrays.toString(byteArray)); // [10, 25, 30, 40, 50]
        // RESIZING THE ARRAY (The manual way)
        // If you need to grow the array, you must create a new, larger one.
        byte[] newByteArray = new byte[10];
        System.arraycopy(byteArray, 0, newByteArray, 0, byteArray.length);
        // Now you can add more elements to the new larger array...
        newByteArray[5] = 60;
        System.out.println("New larger array: " + java.util.Arrays.toString(newByteArray));
    }
}

Advantages of byte[]

  • Extremely Memory Efficient: Only stores the actual byte values with minimal overhead.
  • Fastest Performance: No object creation or garbage collection associated with adding/removing elements.
  • Simplicity: For a fixed-size or manually resized collection of bytes, it's the simplest and most direct solution.

Disadvantages of byte[]

  • Fixed Size: You cannot add or remove elements from the middle of the array without manually creating a new array and copying elements (as shown above).
  • Less Convenient API: It lacks the convenient methods of ArrayList like add(), remove(), contains(), size(), etc. You have to manage everything with indexes.

Solution 3: The Best of Both Worlds - ByteArrayBuffer

If you need the dynamic resizing and convenience of an ArrayList with the memory and performance efficiency of a byte[], the best tool is an external library. The most popular choice is Apache Commons Lang.

Its ByteArrayBuffer class is designed for exactly this purpose.

First, add the dependency to your pom.xml (Maven):

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.14.0</version> <!-- Use the latest version -->
</dependency>

Example:

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.mutable.MutableByte;
public class ByteArrayBufferExample {
    public static void main(String[] args) {
        // Create a ByteArrayBuffer with an initial capacity
        org.apache.commons.lang3.mutable.ByteArrayBuffer buffer = new org.apache.commons.lang3.mutable.ByteArrayBuffer(10);
        // ADDING ELEMENTS (No autoboxing!)
        buffer.append((byte) 10);
        buffer.append((byte) 20);
        buffer.append((byte) 30);
        buffer.append((byte) 40);
        System.out.println("Buffer content: " + buffer); // Uses a nice toString() implementation
        // ACCESSING ELEMENTS
        byte firstByte = buffer.buffered()[0]; // Access the underlying byte[] array
        System.out.println("First element: " + firstByte); // 10
        // MODIFYING AN ELEMENT
        buffer.setByte(1, (byte) 25);
        System.out.println("Buffer after modification: " + buffer);
        // REMOVING ELEMENTS (This is where it shines over a plain byte[])
        buffer.remove(2); // Removes the byte at index 2
        System.out.println("Buffer after removal: " + buffer); // [10, 25, 40]
        // GETTING THE FINAL byte[]
        byte[] finalArray = buffer.toByteArray();
        System.out.println("Final byte[] array: " + java.util.Arrays.toString(finalArray)); // [10, 25, 40]
    }
}

Summary and Recommendation

Method Use Case Memory Performance Convenience Dynamic Resizing?
ArrayList<Byte> Quick and simple, non-critical path code. High Slow High Yes
分享:
扫描分享到社交APP
上一篇
下一篇