Java使用者的延期执行
在前面的博客文章(“ 延遲執(zhí)行Java的供應商 “),我引用礁HORSTMANN的陳述書中‘ 的Java SE8為真的很急關于lambda表達式’,‘所有的lambda表達式的點被推遲執(zhí)行 。’ Horstmann在最后一年為Dobb博士的雜志寫了一篇名為“ Java 8中的Lambda表達式 ”的文章,其中他使用不同的術語寫了類似的聲明,“ Lambda表達式是可以傳遞的代碼塊,因此可以之后執(zhí)行一次,一次或多次。”
在該較早的文章中 ,我研究了JDK中的lambda表達式如何與標準功能接口Supplier一起使用,以在“僅在必要時提供”單個值且未傳遞任何參數(shù)的情況下支持延遲執(zhí)行。 在本文中,我重點介紹JDK提供的示例,這些示例使用Consumer標準功能接口“僅在必要時”“使用”或“處理”特定代碼塊。 Supplier接受任何參數(shù)并僅返回一個響應,而Consumer接受一個或多個參數(shù)并且不返回響應。 在Supplier上調用的方法是get()方法,并且是Consumer的accept(T)方法。 根據定義, Consumer預計將有“副作用”,因為它“消耗”所提供的代碼塊。
java.util.function軟件包中提供了許多Consumer風格的標準功能接口。 這些都不返回結果(這就是為什么他們是消費者!),但是它們接受的參數(shù)的數(shù)量和類型不同(但是它們都接受至少一個參數(shù))。 這些在這里列出:
- 消費者 –接受單個論點的一般Consumer ,將成為本文大部分示例的關注中心。
- BiConsumer –接受兩個參數(shù),而不是一個參數(shù)(“ 消費者的兩類專業(yè)化”)
- DoubleConsumer –適用于原始double的特殊消費者
- IntConsumer –原始int的專門消費者
- LongConsumer –適用于原始long的專業(yè)消費者
- ObjDoubleConsumer –接受兩個參數(shù)的專用消費者 ,第一個為Object類型,第二個為double類型
- ObjIntConsumer –接受兩個參數(shù)的專用消費者 ,第一個參數(shù)為Object類型,第二個參數(shù)為int類型
- ObjLongConsumer –接受兩個參數(shù)的專用消費者,第一個參數(shù)為Object類型,第二個參數(shù)為long類型
本文的其余部分將研究Consumer和相關類的JDK使用的子集,以幫助演示它們如何以及何時有用。
偷看流元素流
在博客文章“ 使用Stream.peek窺視Java Streams內部 ”中,我討論了可用于查看流中流動元素的中間操作 Stream.peek(Consumer) 。 這對于了解各種流操作對其各自的流元素所做的操作非常有用。 一種常見的實現(xiàn)方法是讓提供給peek方法的Consumer是對System.out的調用。 println將當前處理的流元素打印到標準輸出(或記錄該元素或將其打印到標準錯誤)。 Javadoc文檔中為Stream.peek(Consumer)方法提供了一個示例:
Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("Filtered value: " + e)).map(String::toUpperCase).peek(e -> System.out.println("Mapped value: " + e)).collect(Collectors.toList());由于println(-)方法的各種重載版本都接受參數(shù),但不返回任何內容,因此它們完全符合“ Consumer”的概念。
在迭代流元素上指定操作
盡管Stream.peek(Consumer)是一個中間操作,但Stream提供了另外兩個接受Consumer方法,它們都是終端操作 ,并且都是“針對每個”方法。 方法Stream.forEach(Consumer)是一種對流的元素以“顯式不確定性”的方式執(zhí)行由提供的Consumer指定的操作的方法。 如果該流具有遇到順序,則Stream.forEachOrdered(Consumer)方法將以所提供的Consumer以流的“ 遇到順序 ”執(zhí)行指定的操作。 在這兩種方法的情況下,基于Consumer的“動作”應為“ 不干擾” 。 兩種方法都在下面演示。
Set.of("one", "two", "three", "four").stream().forEach(i -> out.println(i.toUpperCase()));Stream.of("one", "two", "three", "four").forEach(i -> out.println(i.toUpperCase()));List.of("one", "two", "three", "four").stream().forEachOrdered(i -> out.println(i.toUpperCase()));Stream.of("one", "two", "three", "four").forEachOrdered(i -> out.println(i.toUpperCase()));上面的示例看起來非常相似。 當使用并行流處理時, forEach可能導致與forEachOrdered截然不同的結果的最明顯情況是。 在這種情況下,它將使大多數(shù)發(fā)送者使用forEach而不是forEachOrdered 。
在可迭代元素上指定操作
前面的代碼示例顯示了使用Stream.forEach(Consumer)方法來迭代流。 這些示例還演示了如何通過首先在這些集合上調用stream()對Set和List進行此操作。 有方便的方法,但是,通過限定可迭代和執(zhí)行由這些集合的實現(xiàn),其接受一個Consumer ,并允許使用該集合的迭代forEach方法。 下一個代碼清單中顯示了此示例。
Set.of("one", "two", "three", "four").forEach(i -> out.println(i.toUpperCase())); List.of("one", "two", "three", "four").forEach(i -> out.println(i.toUpperCase()));盡管在上面的示例中使用了集合,但是實現(xiàn)Iterable的所有對象通常都將支持forEach方法(或違反接口的廣告約定)。
指定映射條目迭代時的操作
盡管Java的Map接口沒有像Set和List那樣擴展Iterable接口,但是Java Map仍然具有類似的功能,可以指定使用者“消費” Map每個條目。 因為Map有兩個輸入參數(shù)(鍵和值),所以它的forEach方法接受BiConsumer而不是到目前為止本文中討論的Consumer 。 接下來顯示一個簡單的示例。
Map.of("Denver", "Colorado","Cheyenne", "Wyoming","Salt Lake City", "Utah","Boise", "Idaho").forEach((c, s) -> out.println(c + " is the capital of " + s));走棧
StackWalker是JDK 9的一個受歡迎的擴展,它提供了一種線程安全的方法來細讀堆棧跟蹤,并且是對StackTraceElement方法的重大改進。 對于開發(fā)人員來說,使用StackWalker.walk(Function)可能更常見,但是這篇文章是關于Consumer ,因此重點是StackWalker.forEach(Consumer) 。 此方法類似于先前討論的Stream.forEach和Iterable.forEach方法,并在下一個代碼清單中進行了演示。
StackWalker.getInstance().forEach(out::println);盡管JDK對Consumer , BiConsumer以及其他類型的標準Consumer樣式功能接口有更多的JDK使用 ,但本文中我要介紹的最后一個示例來自Optional類。
僅在存在時應用
方法Optional.ifPresent(Consumer)和Optional.ifPresentOrElse(Consumer)推遲執(zhí)行提供的Consumer ,以便僅在Optional不是“空”(包含非null值)的情況下才調用提供的Consumer 。 這是一個簡單但功能強大的概念,而簡單且人為的示例說明了它們是如何工作的。
public void demonstrateOptionalIfPresent() {getMiddleName(true).ifPresent(n -> out.println("Middle Name: " + n)); }public void demonstrateOptionalIfPresentOrElse() {getMiddleName(false).ifPresentOrElse(n -> out.println("Middle Name: " + n),() -> displayMissingMiddleName()); }private Optional<String> getMiddleName(final boolean present) {return present ? Optional.of("Wayne") : Optional.empty(); }private void displayMissingMiddleName() {out.println("No middle name provided!"); }如上面的代碼清單所示,如果Optional不為空,則Optional.ifPresent和JDK 9引入的Optional.ifPresentOrElse()僅調用提供的Consumer 。 如果Optional為空,則ifPresent方法不執(zhí)行任何操作,而ifPresentOrElse調用第二個參數(shù)( Runnable )。
接受一個或多個參數(shù)且不返回任何結果的標準Java功能接口包括一般的Consumer以及某些專門的使用者。 這些對于將執(zhí)行推遲到給定條件發(fā)生之前(例如迭代或確定存在)有用,并且在該條件發(fā)生時要應用的行為涉及一個或多個輸入自變量,而無需提供響應。 GitHub上提供了本文中顯示的源代碼示例。
翻譯自: https://www.javacodegeeks.com/2018/06/deferred-execution-java-consumer.html
總結
以上是生活随笔為你收集整理的Java使用者的延期执行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 同人文是什么意思 同人文是指什么
- 下一篇: 人生四大喜和四大悲 人生四大喜和四大悲是