簡體   English   中英

Java 8重構lambda表達式

[英]Java 8 refactoring lambda expressions

我想創建一個使用lambda表達式應用常見統計信息的簡單類。 我想知道如何避免在statistic()方法中使用switch case?

例如,我可能想要編寫一個新的lambda來計算列表的方差等。

謝謝。

public class DescriptiveStatistics {

    public static void main(String[] args) {
        List<Double> numbers = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
        numbers.stream().forEach(n-> System.out.print(n + " "));
        System.out.println();
        System.out.println("Descriptive statistics");
        System.out.println("Sum: " + statistic(numbers, "Sum"));
        System.out.println("Max: " + statistic(numbers, "Max"));
        System.out.println("Min: " + statistic(numbers, "Min"));
        System.out.println("Average: " + statistic(numbers, "Average"));
        System.out.println("Count: " + statistic(numbers, "Count"));
    }

    private static double statistic(List<Double> numbers, String function) {
        switch (function.toLowerCase()) {
            case "sum":
                return numbers.stream().mapToDouble(Double::doubleValue).sum();
            case "max":
                return numbers.stream().mapToDouble(Double::doubleValue).max().getAsDouble();
            case "min":
                return numbers.stream().mapToDouble(Double::doubleValue).min().getAsDouble();
            case "average":
                return numbers.stream().mapToDouble(Double::doubleValue).average().getAsDouble();
            case "count":
                return numbers.stream().mapToDouble(Double::doubleValue).count();
        }
        return 0;
    }

我想到了這樣的方法

private static double newStatistics(List<Double> numbers, Function<Double, Double> function){
        return  numbers.stream().mapToDouble(Double::doubleValue).function();
    }

為什么不簡單地使用DoubleStream#summaryStatistics或應用類似的模式?

您甚至可以擴展該類以添加自定義方法,例如方差,偏度和峰度,例如:

/**
 * Algorithms derived from: Philippe Pébay, Formulas for Robust, One-Pass Parallel
 * Computation of Covariances and Arbitrary-Order Statistical Moments.
 */
public class MoreDoubleStatistics extends DoubleSummaryStatistics {

    private double M1, M2, M3, M4;

    @Override
    public void accept(double x) {
        super.accept(x);

        long n = getCount();

        double delta = x - M1;                       // δ
        double delta_n = delta / n;                  // δ / n
        double delta2_n = delta * delta_n;           // δ^2 / n
        double delta2_n2 = delta_n * delta_n;        // δ^2 / n^2
        double delta3_n2 = delta2_n * delta_n;       // δ^3 / n^2
        double delta4_n3 = delta3_n2 * delta_n;      // δ^4 / n^3

        M4 += (n - 1) * (n * n - 3 * n + 3) * delta4_n3
                + 6 * M2 * delta2_n2
                - 4 * M3 * delta_n;
        M3 += (n - 1) * (n - 2) * delta3_n2
                - 3 * M2 * delta_n;
        M2 += (n - 1) * delta2_n;
        M1 += delta_n;
    }

    @Override
    public void combine(DoubleSummaryStatistics other) {
      throw new UnsupportedOperationException(
              "Can't combine a standard DoubleSummaryStatistics with this class");
    }

    public void combine(MoreDoubleStatistics other) {
        MoreDoubleStatistics s1 = this;
        MoreDoubleStatistics s2 = other;

        long n1 = s1.n();
        long n2 = s2.n();
        long n = n1 + n2;

        double delta = s2.M1 - s1.M1;                // δ
        double delta_n = delta / n;                  // δ / n
        double delta2_n = delta * delta_n;           // δ^2 / n
        double delta2_n2 = delta_n * delta_n;        // δ^2 / n^2
        double delta3_n2 = delta2_n * delta_n;       // δ^3 / n^2
        double delta4_n3 = delta3_n2 * delta_n;      // δ^4 / n^3

        this.M4 = s1.M4 + s2.M4 + n1 * n2 * (n1 * n1 - n1 * n2 + n2 * n2) * delta4_n3
                + 6.0 * (n1 * n1 * s2.M2 + n2 * n2 * s1.M2) * delta2_n2
                + 4.0 * (n1 * s2.M3 - n2 * s1.M3) * delta_n;

        this.M3 = s1.M3 + s2.M3 + n1 * n2 * (n1 - n2) * delta3_n2
                + 3.0 * (n1 * s2.M2 - n2 * s1.M2) * delta_n;

        this.M2 = s1.M2 + s2.M2 + n1 * n2 * delta2_n;

        this.M1 = s1.M1 + n2 * delta;

        super.combine(other);
    }

    private long n() { return getCount(); }

    public double mean() { return getAverage(); }
    public double variance() { return n() <= 1 ? 0 : M2 / (n() - 1); }
    public double stdDev() { return sqrt(variance()); }
    public double skew() { return M2 == 0 ? 0 : sqrt(n()) * M3/ pow(M2, 1.5); }
    public double kurtosis() { return M2 == 0 ? 0 : n() * M4 / (M2 * M2) - 3.0; }
}

將方法統計信息String參數替換為函數類型 ,該函數類型接受DoubleStream並返回聚合。

private static double statistic(List<Double> numbers,
                                ToDoubleFunction<DoubleStream> function) {
    return function.applyAsDouble(
        numbers.stream().mapToDouble(Double::doubleValue));
}

現在,您可以按如下方式調用方法,而不對流上的不同操作使用switch語句:

System.out.println("Sum: " + statistic(numbers, s -> s.sum()));
System.out.println("Max: " + statistic(numbers, s -> s.max().getAsDouble()));
System.out.println("Min: " + statistic(numbers, s -> s.min().getAsDouble()));
System.out.println("Average: " + statistic(numbers, s -> s.average().getAsDouble()));
System.out.println("Count: " + statistic(numbers, s -> s.count()));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM