日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

findfirst_当心findFirst()和findAny()

發布時間:2023/12/3 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 findfirst_当心findFirst()和findAny() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

findfirst

過濾Java 8 Stream ,通常使用findFirst()或findAny()來獲取在過濾器中幸存的元素。 但這可能并不能真正實現您的意思,并且可能會出現一些細微的錯誤。

那么

從我們的Javadoc( 此處和此處 )可以看出,這兩種方法都從流中返回任意元素-除非流具有遇到順序 ,在這種情況下, findFirst()返回第一個元素。 簡單。

一個簡單的示例如下所示:

public Optional<Customer> findCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).findFirst(); }

當然,這只是舊的for-each-loop的漂亮版本:

public Optional<Customer> findCustomer(String customerId) {for (Customer customer : customers)if (customer.getId().equals(customerId))return Optional.of(customer);return Optional.empty(); }

但是,這兩種變體都包含相同的潛在錯誤:它們是基于隱含的假設建立的,即只有一個具有任何給定ID的客戶。

現在,這可能是一個非常合理的假設。 也許這是一個已知的不變式,由系統的專用部分保護,并由其他人員依賴。 在這種情況下,這完全可以。

通常,代碼依賴于唯一的匹配元素,但沒有做任何斷言。

但是在很多情況下,我不是在野外看到的。 也許客戶只是從外部來源加載的,這些來源無法保證其ID的唯一性。 也許現有的錯誤允許兩本書具有相同的ISBN。 也許搜索詞允許出乎意料的許多意外匹配(有人說過正則表達式嗎?)。

通常,代碼的正確性取決于以下假設:存在與條件匹配的唯一元素,但它不執行或斷言該元素。

更糟糕的是,不當行為完全是由數據驅動的,可能會在測試期間將其隱藏。 除非考慮到這種情況,否則我們可能會完全忽略它,直到它在生產中出現為止。

更糟糕的是,它默默地失敗了! 如果只有一個這樣的元素的假設被證明是錯誤的,我們將不會直接注意到這一點。 取而代之的是,系統會在觀察到影響并查明原因之前微妙地運行一段時間。

因此,當然, findFirst()和findAny()本質上沒有錯。 但是,使用它們很容易導致建模域邏輯中的錯誤。

Steven Depolo在CC-BY 2.0下發布

快速失敗

因此,讓我們解決這個問題! 假設我們非常確定最多有一個匹配元素,如果沒有,我們希望代碼快速失敗 。 通過循環,我們必須管理一些難看的狀態,它看起來如下:

public Optional<Customer> findOnlyCustomer(String customerId) {boolean foundCustomer = false;Customer resultCustomer = null;for (Customer customer : customers)if (customer.getId().equals(customerId))if (!foundCustomer) {foundCustomer = true;resultCustomer = customer;} else {throw new DuplicateCustomerException();}return foundCustomer? Optional.of(resultCustomer): Optional.empty(); }

現在,流為我們提供了更好的方法。 我們可以使用經常被忽略的reduce, 文檔中對此說 :

執行減少有關此流的元件,使用締合累積功能,并返回一個可選描述的縮小值,如果有的話。 這等效于:

流減少

boolean foundAny = false; T result = null; for (T element : this stream) {if (!foundAny) {foundAny = true;result = element;}elseresult = accumulator.apply(result, element); } return foundAny ? Optional.of(result) : Optional.empty();

但不限于順序執行。

看起來不像上面的循環嗎?! 瘋狂的巧合...

因此,我們需要的是一個累加器,該累加器會在調用后立即拋出所需的異常:

public Optional<Customer> findOnlyCustomerWithId_manualException(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce((element, otherElement) -> {throw new DuplicateCustomerException();}); }

這看起來有些奇怪,但它確實可以滿足我們的要求。 為了使它更具可讀性,我們應該將其放入Stream實用工具類中并給它起一個漂亮的名字:

public static <T> BinaryOperator<T> toOnlyElement() {return toOnlyElementThrowing(IllegalArgumentException::new); }public static <T, E extends RuntimeException> BinaryOperator<T> toOnlyElementThrowing(Supplier<E> exception) {return (element, otherElement) -> {throw exception.get();}; }

現在我們可以這樣稱呼它:

// if a generic exception is fine public Optional<Customer> findOnlyCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce(toOnlyElement()); }// if we want a specific exception public Optional<Customer> findOnlyCustomer(String customerId) {return customers.stream().filter(customer -> customer.getId().equals(customerId)).reduce(toOnlyElementThrowing(DuplicateCustomerException::new)); }

目的顯示代碼如何?

這將實現整個流。

應該注意的是,與findFirst()和findAny() ,這當然不是短路操作 ,它將實現整個流。 也就是說,如果確實只有一個元素。 當然,一旦遇到第二個元素,處理就會停止。

反射

我們已經看到findFirst()和findAny()如何不足以表示流中最多剩余一個元素的假設。 如果我們要表達該假設,并確保在違反該代碼時快速失敗,則需要reduce(toOnlyElement()) 。

  • 您可以在GitHub上找到代碼并隨意使用-它在公共領域。

首先感謝Boris Terzic使我意識到這種意圖不匹配。

翻譯自: https://www.javacodegeeks.com/2016/02/beware-findfirst-findany.html

findfirst

總結

以上是生活随笔為你收集整理的findfirst_当心findFirst()和findAny()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。