Of course! In Java, a List of double values is a common requirement. However, due to Java's generics, you cannot directly use a primitive type like double as a type parameter. You must use its corresponding wrapper class, Double.

Here’s a complete guide covering the best ways to work with a List of double values in Java, from the classic approach to modern, more efficient alternatives.
The Classic Approach: List<Double>
This is the most straightforward and widely understood method. You create a List that holds objects of the Double class.
Key Characteristics:
- Flexibility: Can hold
nullvalues. - Memory Overhead: Each
doubleis wrapped in aDoubleobject, which consumes more memory than a primitivedouble. - Performance: Autoboxing (converting
doubletoDouble) and unboxing (convertingDoubletodouble) add a small performance overhead.
Code Example:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DoubleListExample {
public static void main(String[] args) {
// 1. Create a List of Double using ArrayList
List<Double> doubleList = new ArrayList<>();
// 2. Add elements (autoboxing happens here: double -> Double)
doubleList.add(10.5);
doubleList.add(25.0);
doubleList.add(99.99);
doubleList.add(null); // A List<Double> can hold null values
System.out.println("Initial list: " + doubleList);
// 3. Add all elements from another collection
List<Double> moreDoubles = Arrays.asList(15.2, 30.7);
doubleList.addAll(moreDoubles);
System.out.println("After adding more elements: " + doubleList);
// 4. Access an element (unboxing happens here: Double -> double)
double firstElement = doubleList.get(0); // firstElement is a primitive double
System.out.println("First element: " + firstElement);
// 5. Iterate over the list
System.out.println("\nIterating with a for-each loop:");
for (Double value : doubleList) {
// The 'value' variable is of type Double
if (value != null) {
System.out.println("Value: " + value + ", its square is: " + (value * value));
} else {
System.out.println("Found a null value.");
}
}
// 6. Calculate the sum
double sum = 0.0;
for (Double num : doubleList) {
if (num != null) {
sum += num; // Unboxing happens during addition
}
}
System.out.println("\nSum of all elements: " + sum);
}
}
The Modern & Efficient Approach: DoubleStream (Java 8+)
For any numerical operations (sum, average, min, max, etc.), using a DoubleStream is highly recommended. It avoids the overhead of List<Double> and is designed for high-performance numerical computations.
You can get a DoubleStream from a List<Double> or, more efficiently, directly from a primitive double array.

Code Example:
import java.util.Arrays;
import java.util.List;
import java.util.OptionalDouble;
public class DoubleStreamExample {
public static void main(String[] args) {
// You can start from a List<Double>...
List<Double> doubleList = Arrays.asList(10.5, 25.0, 99.99, 15.2, 30.7);
// ...but it's more efficient to work with a primitive double array
double[] doubleArray = {10.5, 25.0, 99.99, 15.2, 30.7};
System.out.println("Working with a DoubleStream from a double array:");
// 1. Calculate the sum
double sum = Arrays.stream(doubleArray).sum();
System.out.println("Sum: " + sum);
// 2. Calculate the average
OptionalDouble average = Arrays.stream(doubleArray).average();
average.ifPresent(avg -> System.out.println("Average: " + avg));
// 3. Find the maximum value
double max = Arrays.stream(doubleArray).max().orElse(Double.NaN);
System.out.println("Max value: " + max);
// 4. Find the minimum value
double min = Arrays.stream(doubleArray).min().orElse(Double.NaN);
System.out.println("Min value: " + min);
// 5. Filter and collect results back into a new list
// Note: This converts the stream back to a List<Double>
List<Double> largeNumbers = Arrays.stream(doubleArray)
.filter(d -> d > 20.0)
.boxed() // Convert double to Double
.toList(); // Collect into an unmodifiable list
System.out.println("Numbers greater than 20.0: " + largeNumbers);
}
}
The High-Performance Approach: double[] (Primitive Array)
If you only need a fixed-size collection and your primary concerns are memory usage and raw speed, a primitive double[] array is the best choice.
Key Characteristics:
- Performance: Fastest possible access and storage. No autoboxing/unboxing overhead.
- Memory: Most memory-efficient. No object headers are created for each element.
- Drawbacks:
- Fixed Size: Its size cannot be changed after creation (you have to create a new one).
- No Rich API: It doesn't have the useful methods of the
Listinterface (e.g.,add(),remove(),contains()). - Cannot hold
null: It can only holddoublevalues.
Code Example:
import java.util.Arrays;
public class DoubleArrayExample {
public static void main(String[] args) {
// 1. Create and initialize an array
double[] prices = new double[5];
prices[0] = 19.99;
prices[1] = 25.50;
prices[2] = 10.00;
prices[3] = 100.25;
prices[4] = 5.75;
System.out.println("Initial array: " + Arrays.toString(prices));
// 2. Access an element
double secondPrice = prices[1];
System.out.println("Second price: " + secondPrice);
// 3. Modify an element
prices[0] = 15.49;
System.out.println("After modification: " + Arrays.toString(prices));
// 4. Calculate the sum using a loop (most efficient for arrays)
double total = 0.0;
for (int i = 0; i < prices.length; i++) {
total += prices[i];
}
System.out.println("Total sum: " + total);
// 5. Sort the array
Arrays.sort(prices);
System.out.println("Sorted array: " + Arrays.toString(prices));
}
}
Third-Party Libraries: Eclipse Collections, FastUtil
For very large-scale applications where performance is critical, libraries like Eclipse Collections and FastUtil provide specialized List implementations for primitives. They offer the rich API of a List with the performance of a primitive array.
Example with FastUtil:
You need to add the FastUtil dependency to your project (e.g., in Maven):
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.9</version>
</dependency>
Code Example:
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList;
public class FastUtilExample {
public static void main(String[] args) {
// 1. Create a DoubleList (it's a List<double> equivalent)
DoubleList fastDoubleList = new DoubleArrayList();
// 2. Add elements (no autoboxing!)
fastDoubleList.add(10.5);
fastDoubleList.add(25.0);
fastDoubleList.add(99.99);
System.out.println("FastUtil DoubleList: " + fastDoubleList);
// 3. Get an element (no unboxing!)
double firstElement = fastDoubleList.getDouble(0);
System.out.println("First element: " + firstElement);
// 4. It has a rich API like a regular List
fastDoubleList.set(1, 30.0);
System.out.println("After setting index 1 to 30.0: " + fastDoubleList);
}
}
Summary: Which One Should You Choose?
| Method | Best For | Pros | Cons |
|---|---|---|---|
List<Double> |
General purpose, flexibility. | Standard Java API, rich methods, can hold null. |
Slower due to autoboxing, higher memory usage. |
DoubleStream |
Numerical operations (sum, avg, etc.). | Highly optimized, concise, modern Java style. | Requires Java 8+, less convenient for simple storage. |
double[] |
Maximum performance and memory efficiency. | Fastest, smallest memory footprint. | Fixed size, limited API, no nulls. |
DoubleList (FastUtil) |
Large datasets where you need both a List API and primitive speed. |
Best of both worlds: List API + primitive speed. |
Requires an external dependency. |
Recommendation:

- For most general-purpose use cases,
List<Double>is perfectly fine and easy to work with. - If you are performing mathematical calculations, always prefer
DoubleStream. - If you are in a performance-critical loop or dealing with millions of numbers, use a
double[]. - If you need a dynamically-sized
List-like structure with primitive performance in a large project, consider FastUtil or Eclipse Collections.
