2013-02-23 81 views
5

爲什麼不執行Math.max a variadic function爲什麼Math.max(double a,double b)是可變的?

它可以得到實現這樣的:

public class Main { 
    public static double max(double... values) { 
     double max = Double.NEGATIVE_INFINITY; 
     for (double tmp : values) { 
      max = max < tmp ? tmp : max; 
     } 
     return max; 
    } 

    public static void main(String[] args) { 
     // This works fine: 
     System.out.println(max(-13, 12, 1337, 9)); 

     // This doesn't work: 
     // System.out.println(Math.max(-13, 12, 1337)); 
    } 
} 

有它爲什麼不這樣實現的任何原因?

+4

數學中的Java 1.0中引入的。 1.5中的可變參數... – Kai 2013-02-23 11:45:52

回答

3

雖然其他人已經回答了爲什麼Math.max不是可變參數,但他們沒有回答爲什麼在引入可變參數函數時沒有創建這種方法。

我甚至不知道它(有一個open bug-report),所以我只能猜測:

這是事實,它不是在Math實現,但如果我們看看Collections有以下方法:

public static <T extends Object & Comparable<? super T>> T max(
    Collection<? extends T> coll) { 
    ... 
} 

雖然類型簽名長相醜陋(它需要有足夠的靈活性來處理協方差和逆變),它可以很容易地與Collections.max(Arrays.asList(-13, 12, 1337, 9));使用所有的功能之後,只是在不同的地方。

更好:這種方法不僅可以處理雙打,而且可以處理所有類型的接口。

儘管如此,無論您的建議解決方案還是Collections中的解決方案都是面向對象的,它們只是靜態方法。幸運的是,與JDK8這將改變:

import java.util.Arrays; 
import java.util.List; 
import java.util.Optional; 

int max(List<Integer> list) { 
    Optional<Integer> opt = list.stream().max((a,b) -> a-b); 
    return opt.orElse(Integer.MAX_VALUE); 
} 

max(Arrays.asList(-13, 12, 1337, 9)); // 1337 
max(Arrays.asList()); // 2147483647 

對於即將發行的集合庫在Project Lambda修改,以更加面向對象。在上面的例子中,Lambdas用來提供一個簡單易讀的方法來確定最大元素。下面將工作太:

import static java.util.Comparators.naturalOrder; 

Arrays.asList(-13, 12, 1337, 9) 
    .stream() 
    .max(naturalOrder()) 
    .ifPresent(System.out::println); // 1337 

代替max人們也可以使用更高階的功能reduce

Arrays.asList(-13, 12, 1337, 9) 
    .stream() 
    .reduce((a,b) -> a > b ? a : b) 
    .ifPresent(System.out::println); // 1337 

另一個細節是使用Optional。這是一種簡化錯誤處理的類型,由於高階函數的組成,如上例所示。

拉姆達方案有幾個優點,使其不必要實現Math.max的可變參數形式:

  1. 它是面向對象的
  2. 這是多態的。這意味着它可以與所有類型的集合(ListSetStreamIterator等)
  3. 它的表現力和容易理解
  4. 的它允許用戶對即時並行使用。只需將.stream()更改爲.parallelStream()
2

因爲它的存在時間比java中存在的可變參數函數更長(在java 5中介紹過),並且沒有太多的需求來更新它,因爲正如你剛纔所顯示的那樣,它很容易做你自己。

也有涉及可變參數的方法作爲數組的ahidden性能損失(雙[])將被從你的參數創建

+0

你知道Java具有哪些版本的可變參數函數嗎? 另一個問題:如果有'max(double ... values)'和'max(double a,double b)',java如何決定應該採用哪個函數?我已經嘗試過了,它需要非可變參數,但是我沒有在JLS中找到它。 – 2013-02-23 11:47:31

+0

@moose - java 5(我已經包含一個鏈接)。同樣,因爲dasblinkenlight說vararg方法實際上是接受一個數組的方法 - 在這種情況下是double [],所以對於只有2個參數,非vararg方法是更好的匹配。 – radai 2013-02-23 11:50:44

5

java.lang.Math已在JDK 1.0被引入在幕後,長可變參數函數之前在Java 5中引入語言。

另外,效率是一個問題:如果大多數情況下需要兩個元素,那麼將它們「內聯」傳遞會更快,而不需要創建中間數組來保存它們。這也避免了在實現中設置循環的成本。

0

Math.max()可以追溯到JDK 1.0,而可變參數的功能已不存在,直到Java 5的

1

Math.max已自JDK 1.0,引入參數語法的變量#很久以前。這並不是說該方法無法按照您的建議進行更新。有時候庫方法的定義或實現會改變,但這很少見。大多數情況下,新方法被添加到類中,而不是修改現有的方法。

Max的新實現實際上是方法重載的一種情況,因爲現有方法和新var args方法可能在同一個類中並排存在。所以雖然它當然可以取代現有的方法,但它也可能只是Math類的一個補充。所以我認爲它應該被添加。我們可以離開現有方法的事實消除了新實現可能引起的對性能的任何擔憂。

無論如何,Java n和Java n + 1之間可以改變的文化正在改變。例如,文件訪問類和java.sql.Connection已從Java 6更改爲Java 7,因爲在Java 7中它們現在實現AutoCloseable。 Java 9實際上是從project jigsaw中刪除一些方法。

我可以想到沒有更正Math.max的有效原因。也許到現在爲止沒有人提出過。你在看這個,Mark Reinhold

2

Java 8已經使用流實現了數字操作,這非常靈活。舉個例子:

DoubleStream.of(-13, 12, 1337, 9).max().getAsDouble() 

不像自制的那麼簡單,但仍然直接,快速,更靈活。

例如,利用多核心的只需要一個函數調用:

stream.parallel().max().getAsDouble() 

毫無意義在這種情況下,由於發現最大速度非常快,即使雙 - 你需要數以百萬計的雙打看毫秒之差。 但是,如果有其他處理,那麼它可以快速加速。

或者你也可以找到最小值,平均值,總和等全部一氣呵成,只用系統類:

DoubleSummaryStatistics stat = DoubleStream.of(-13, 12, 1337, 9).summaryStatistics(); 
System.out.println(stat.getMin()); 
System.out.println(stat.getAverage()); 
System.out.println(stat.getMax()); 
System.out.println(stat.getCount()); 
System.out.println(stat.getSum()); 
相關問題