Работает ли анализ побега 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
в очень простой результат объекта.
Сохранение всей этой логики очень локализованным и предотвращение изменения результата вызывающими лицами позволяет легко рассуждать о том, что происходит. Ваш пример кода с массивами длины один нарушает оба этих принципа и усложняет понимание, использование или сопровождение кода.
С другой стороны, если вы можете использовать значения сразу после их вычисления, вы можете пропустить класс и просто вычислить их все в строке. Вы можете сделать это через цикл или рассчитать их отдельно, используя встроенную функциональность.