Работает ли анализ побега Java для массивов только с одним элементом?

Фон:

Когда вы извлекаете методы из длинных частей кода, вы часто сталкиваетесь с проблемой вызова по значению с примитивными переменными. Вы не можете изменить эти примитивные параметры в извлеченном методе, чтобы вызывающая сторона увидела изменения. Вы можете избежать этого, сделав примитивную переменную массивом только с одним элементом. Тогда он эффективно используется по ссылке. Однако теперь это объект в куче. Является ли анализ побега 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);
    }
}

1 ответ

Вот лучший способ сделать это:

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 в очень простой результат объекта.

Сохранение всей этой логики очень локализованным и предотвращение изменения результата вызывающими лицами позволяет легко рассуждать о том, что происходит. Ваш пример кода с массивами длины один нарушает оба этих принципа и усложняет понимание, использование или сопровождение кода.

С другой стороны, если вы можете использовать значения сразу после их вычисления, вы можете пропустить класс и просто вычислить их все в строке. Вы можете сделать это через цикл или рассчитать их отдельно, используя встроенную функциональность.

Другие вопросы по тегам