2017-06-09 99 views
11

我想知道,有沒有辦法擺脫findFirst().get()的警告,而不使用.orElse()如果我100%知道每次都有結果,所以我永遠不會有一個NoSuchElementException。例如,讓我們看看下面的代碼:Java8:流find第一結果

List<String> myList = new ArrayList<>(); 
    myList.add("Test"); 
    myList.add("Example"); 
    myList.add("Sth"); 

    String fisrstString = myList.stream().findFirst().get(); // here I surely get "Test" 

我不知道其他的IDE-請客,這一點,但我的IDE(的IntelliJ)如何對待,作爲一個警告('Optional.get()' without 'isPresent()')。我可能認爲它不」我知道有什麼方法可以解決這個警告(isPresent()檢查,.orElse(something)),但無用的代碼,所以我不想使用這些解決方案因爲他們太沒必要了。 你有什麼想法我可以做什麼,或解釋如何處理的IDE?

編輯:對不起,NPE,其NoSuchElementException我有這個錯誤,但我認爲這個問題仍然可用。

+2

我認爲有一個選項可以禁用IntelliJ所執行的某些檢查。嘗試在設置 – Sweeper

+0

你找到一個空列表沒有問題,但如果你嘗試獲得1s元素在一個空列表中,你會得到一個*** NoSuchElementException *** –

+0

https://www.jetbrains .com/help/idea/2017.1/suppressing-inspections.html#d927037e65? – slim

回答

9

那麼,至於我,最好的方法是使用功能編程,並繼續使用可選。所以,例如,如果您需要將此字符串傳遞給某個服務,您可以執行以下操作:

String fisrstString = myList.stream().findFirst().get(); 
service.doSomething(fisrstString); 

但是這看起來不太好。相反,你可以使用函數編程的優點,並做到:

myList.stream().findFirst().ifPresent(service::doSomething); 
+0

但我不想打印它,我剛剛寫了字符串,因爲它非常簡單明瞭我想要的內容,但是例如,如果我想將結果傳遞給方法我不能這樣做,所以我必須使用警告。 – Sunflame

+3

@Sunflame你可以將結果傳遞給'ifPresent'中的方法。 '.ifPresent(result - > doSomething(result));' –

+4

@Sunflame Monads的思想,其中'Optional'來自函數式編程。所以對我來說,這是更好的FP的利弊它這種情況下 –

7

首先,你不會得到一個NPE,但NoSuchElementException。第二,它是誰可能肯定;但其他人可能會來,並沒有意識到它不會引發異常。

對於沙箱項目 - 是的,你不會在乎,可以忽略警告;對於生產代碼我不會禁用它(即使你可以)。

最後一點是,如果你確定,爲什麼不拋出異常?

orElseThrow(IAmSureThisWillNotHappenException::new) 
+0

你是對的,我不想禁用這個警告,我只是認爲IntelliJ足夠聰明,知道何時可以得到'NoSuchElementException'。如果結果總是在那裏,那麼我永遠不會得到異常 – Sunflame

+1

@Sunflame,這將需要提前編譯器最有可能......目前沒有這樣的東西可用 – Eugene

+2

你也可以在這裏拋出一個'AssertionError' – gyre

3

您可以流空單沒有問題,但如果你試圖得到一個空的名單上的第1個要素,你會得到一個NoSuchElementException異常

的流API意識到,完美無瑕的,因此他們爲您提供多種方式來處理:

選項1orElse如果沒有第一個元素被發現,你可以返回一個「默認」值

String firstString = myList.stream().findFirst().orElse("Ups!"); 

1選項orElseGet可以使用Supplier<String>,讓後面的String,如果沒有第一個元素被發現

firstString = myList.stream().findFirst().orElseGet(mySupplier); 

2選項orElseThrow你可以拋出一個異常,如果沒有第一個元素被發現

firstString = myList.stream().findFirst().orElseThrow(WhatTerribleFailException::new); 

System.out.println(fisrstString); 
2

IF你知道你的Optional永遠是空的,你可以使用如下@SuppressWarnings註釋:

@SuppressWarnings("ConstantConditions") String foo = Optional.of("bar").get(); 

有時Optional.get會養NullPointerException,例如:

Optional<String> it = Optional.empty(); 
String foo = it.get(); 
      // ^--- throws NullPointerException when this method is invoked 

SO當使用此表達式時,Intellij將報告wa檢查

IF要禁用所有合約的檢查,你可以做以下操作:設置 - >檢查 - >選中的一定的條件&例外選項 - >不要忘記點擊應用按鈕在底部保存您的設置。

IF你不想禁用除了Optional.get() warnnings你可以做以下操作的所有合同的檢查:設置 - >檢查 - >檢查一定的條件&例外選項 - >在右下方有框架可配置Optional.get()警告 - >不要忘記點擊在底部應用按鈕以保存您的設置。

enter image description here

+0

是的I 'm知道'Optional'是如何工作的,所以我知道在這種情況下我可以得到NPE,但在我的情況下,我不會得到任何異常。 (對我來說不是'@ SuppressWarnings',但我不想使用這樣不必要的代碼) – Sunflame

+0

@Sunflame嗨,如果你想禁用這個功能,你可以在腳下看到我編輯的答案。 –

+0

它沒有幫助,警告仍然存在,但我不確定是否禁用了此警告,那麼當它不確定.get()的結果是否爲null時,我會收到警告。 – Sunflame

4

您應使用由findFirst()而不是設法得到它的值(如果它的實際存在)返回的Optional的。

myList.stream() 
    .findFirst() 
    .ifPresent(/* consume the string here, if present */); 

Optional.ifPresent方法接收​​將如果Optional包含非空值僅使用。

的問題是,我們的Java開發人員都習慣勢在必行範式......特別是我們用來獲取對象和它即一個方法:

String myString = "hello"; // getting an object here 

System.out.println(myString); // pushing the object to System.out here 
           // (via the println method) 

隨着返回的Stream.findFirst()你在做上面一樣Optional

String myString = myList.stream() 
    .findFirst() 
    .get(); // getting a string here 

System.out.println(myString); // pushing the string here 

在另一方面,功能模式(包括Optional)通常工作的其他方式:

myList.stream() 
    .findFirst() 
    .ifPresent(myString -> System.out.println(myString)); 

在這裏,你不會得到字符串,然後推它到一些方法。相反,您提供了對OptionalifPresent操作的參數,並讓Optional的實現將值推送給您的參數。換句話說,你用ifPresent的論點包裹的值OptionalifPresent將僅在該值存在時才使用此Consumer參數。

這種拉模式在函數式編程中被看到很多,並且一旦您習慣了它,它將非常有用。它只是要求我們的開發人員以不同的方式開始思考(和編程)。

+1

謝謝你的解釋,你是對的,我有和你說的一樣的經歷,我更喜歡把對象推向一個關心它的方法,在這種情況下,我必須開始思考一點點不同。所以我使用你提出的這個解決方案,你有我的+1,但是我接受@Serghey Bishyr,因爲他是第一個提出這個答案的人。 – Sunflame

+0

@Sunflame不用擔心,沒關係。我只是在寫了我的長答案的時候看到Bishyr的回答,但是我決定不會因爲推拉模式拉布拉布而將其刪除... –

+0

您的回答基本上與我所評論的相同,我想[我的評論](https://stackoverflow.com/questions/44458540/java8-stream-findfirst-result#comment75930588_44458623)也適用於此。 – maaartinus