杰瑞科技汇

Java List如何处理Double类型数据?

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.

Java List如何处理Double类型数据?-图1
(图片来源网络,侵删)

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 null values.
  • Memory Overhead: Each double is wrapped in a Double object, which consumes more memory than a primitive double.
  • Performance: Autoboxing (converting double to Double) and unboxing (converting Double to double) 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.

Java List如何处理Double类型数据?-图2
(图片来源网络,侵删)

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 List interface (e.g., add(), remove(), contains()).
    • Cannot hold null: It can only hold double values.

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:

Java List如何处理Double类型数据?-图3
(图片来源网络,侵删)
  • 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.
分享:
扫描分享到社交APP
上一篇
下一篇