2016-12-18 35 views
2

背景:java逃生分析是否也適用於只有一個元素的數組?

當您從長代碼片斷中提取方法時,通常會遇到基元變量的值調用問題。您不能在提取的方法中更改這些原始參數,以便調用者看到更改。 您可以通過使primitive變量只有一個元素的數組來避免這種情況。然後它被有效地用於通過引用來調用。然而,它現在是堆上的一個對象。 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); 
    } 
} 
+3

EA是一個實現細節,不僅取決於特定的JVM,還取決於JIT的特定版本和決策。您應該寫一個microbenchmark,啓用GC日誌記錄,看看它是否分配 – the8472

+0

我看不到逃生分析出現在圖片中。如果你的'calcFactorial()'方法變熱了,它將被內聯。從那時起,不需要擔心任何方法調用,只需創建一個局部變量並進行更新即可。 – biziclop

+0

我擔心這個例子會很簡單。 – mmirwaldt

回答

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轉換爲非常簡單的結果對象。

保持所有這些邏輯非常本地化,防止調用者修改結果,因此很容易推斷髮生了什麼。長度爲一個數組的示例代碼違反了這兩個原則,並且使其更難理解,使用或維護代碼。

或者,如果您可以在計算它們之後立即使用這些值,則可以跳過該類並將它們全部計算在內。你可以通過一個循環來做到這一點,或使用內置的功能分別計算它們。

相關問題