2

バックグラウンド:

長いコード片からメソッドを抽出すると、プリミティブ変数で値渡しの問題に遭遇することがよくあります。呼び出し元が変更を確認できるように、抽出されたメソッドでこれらのプリミティブ パラメーターを変更することはできません。プリミティブ変数を要素が 1 つだけの配列にすることで、これを回避できます。次に、参照渡しで効果的に使用されます。ただし、現在はヒープ上のオブジェクトです。Java のエスケープ解析は、それを理解して、それにもかかわらずスタックを使用するほど賢いのでしょうか?

次のコードとケースを指定すると、インライン化できませんでした:

public class EscapeAnalysisTest {
    public static void main(String[] args) {
        final Set<Integer> integers = new HashSet<>();
        integers.add(1);
        integers.add(9);
        integers.add(8);
        integers.add(4);
        // and so on ...

        final long[] product = new long[1];
        final long[] sum = new long[1];
        final long[] count = new long[1];
        final int[] max = new int[1];
        final int[] min = new int[1];

        product[0] = 1L;
        max[0] = Integer.MIN_VALUE;
        min[0] = Integer.MAX_VALUE; 

        for (Integer i : integers) {
            calcSomeValues(product, sum, count, max, min, i);
        }

        System.out.println("Product :" + product[0]);   
        System.out.println("Sum :" + sum[0]);   
        System.out.println("Count:" + count[0]);
        System.out.println("Max:" + max[0]);
        System.out.println("Min:" + min[0]);            
    }

    private static void calcSomeValues(final long[] product, final long[] sum, final long[] count, final int[] max,
            final int[] min, Integer i) {
        product[0] *= i;
        sum[0] += i;
        count[0]++;
        max[0] = Math.max(max[0], i);
        min[0] = Math.min(min[0], i);
    }
}
4

1 に答える 1

2

これを行うより良い方法は次のとおりです。

public class Test {
    public static class Summary {
        private long product;
        private long sum;
        private long count;
        private int max;
        private int min;

        private Summary() {
            product = 1;
            sum = 0;
            count = 0;
            max = Integer.MIN_VALUE;
            min = Integer.MAX_VALUE; 
        }

        public long getProduct() { return product; }
        public long getSum() { return sum; }
        public int getCount() { return count; }
        public int getMax() { return max; }
        public int getMin() { return min; }

        public static Summary summarize(Collection<Integer> ints) {
            Summary s = new Summary();

            s.count = ints.size();
            for (Integer i : ints) {
                s.product *= i;
                s.sum += i;

                if (i > s.max) {
                    // You can use Math.max if you want
                    s.max = i;
                }
                if (i < s.min) {
                    // You can use Math.min if you want
                    s.min = i;
                }
            }

            return s;
        }
    }

    public static void main(String[] args) {
        final Set<Integer> integers = new HashSet<>();
        integers.add(1);
        integers.add(9);
        integers.add(8);
        integers.add(4);
        // and so on ...

        Summary s = Summary.summarize(integers);

        System.out.println("Product: " + s.getProduct());
        System.out.println("Sum: " + s.getSum());
        System.out.println("Count: " + s.getCount());
        System.out.println("Max: " + s.getMax());
        System.out.println("Min: " + s.getProduct());
    }
}

あなたが持っている方法で配列を使用するのは奇妙です。やらないでください。これは他のプログラマーを混乱させることになり、言語の使用方法として意図されたものではありません。それは最小の驚きの原則に違反しています。

代わりに、奇妙な領域に入ることなく、システムを機能させる方法を見つけてください。互いに論理的に関連付けられた複数の値があり、それらはすべて同時に計算されます。一緒に使用されるいくつかの値がある場合は、クラスの使用について考える良い機会です。すべての更新を行うクラスと単一のメソッドを使用することで、コードは明確で合理的になります。私が提供したクラスは、(外部コードに関する限り) 実際には不変になります。これは、集計を計算するロジックがすべてsummarizeメソッド内にあり、プライベート属性にアクセスできるため、非常にうまくカプセル化されているためです。(名前はおそらくもっと良いかもしれませんが、例としてはこれで十分だと思います。) のプライベート状態を変更することsummarizeが望ましくない場合は、Summaryインスタンス変数の値を持つ引数と、それらをローカル変数として計算した後、値をコンストラクターに渡すだけでSummary、非常に単純な結果オブジェクトになります。

このすべてのロジックを非常にローカライズし、呼び出し元が結果を変更できないようにすることで、何が起こっているのかを簡単に判断できます。長さ 1 の配列を使用したサンプル コードは、これらの原則の両方に違反しており、コードの理解、使用、または維持を難しくしています。

または、値を計算した直後に値を使用できる場合は、クラスをスキップしてすべてをインラインで計算できます。ループを介してこれを行うか、組み込み機能を使用して個別に計算することができます。

于 2016-12-19T00:23:56.713 に答える