通常,我们编写代码来计算出一堆可用的答案。 让我们看看Java中的情况。
public Widget getAppropriateWidget(CustomerRequest request) { if (shelfstock.contains(request.getBarcode()) { return new ShelfWidget(); } if (backroomStock.contains(request.getBarcode()) { return new BackroomWidget(); } if (supplier.contains(request.getEan()) { return new SupplierWidget(); } return null ; }
您将不得不想象更复杂的场景,隐藏在上面的简化代码后面。 该算法的作用是按优先级顺序尝试选项,直到找到有效的选项,否则将失败,在这种情况下它将不返回任何内容。
我们还要想象一下,由于某些原因,对contains
的调用很昂贵–也许每个对象都隐藏了一个Web服务或复杂的数据库查询。
让我们以两种方式重构上面的代码开始。 让我们使用Optional
,并为每个方法使用子例程。
public Optional<Widget> getAppropriateWidget(CustomerRequest request) { Optional<Widget> shelfWidget = getShelfWidget(request); if (shelfWidget.isPresent()) { return shelfWidget; } Optional<Widget> backroomWidget = getBackroomWidget(request); if (backroomWidget.isPresent()) { return backroomWidget; } Optional<Widget> supplierWidget = getSupplierWidget(request); if (supplierWidget.isPresent()) { return supplierWidget; } return Optional.empty; } // imagine the subsidiary functions
因此,这比未找到的返回null
要好于null
,并且正努力使用子例程来使该函数描述自身,但是存在这样一个问题,即返回的每个Optional
对象都无法链接到责任链。
我们可以作弊:
Optional<Widget> shelfWidget = getShelfWidget(request); Optional<Widget> backroomWidget = getBackroomWidget(request); Optional<Widget> supplierWidget = getSupplierWidget(request); return firstNonEmpty(shelfWidget, backroomWidget, supplierWidget); private static Optional<Widget> firstNonEmpty( Optional<Widget> ... options) { return Arrays.stream(options) .filter(Optional::isPresent) .findFirst() // makes an optional of optional here... .orElse(Optional.empty()); }
上面的代码更好一些,但是现在必须在选择一个之前预先计算所有可能的答案。 如果答案很快就会出现,我们就需要避免成本高昂的期权计算。
带有可选解决方案的第一个过去的帖子
将流或varargs数组传递给一个函数,该函数由将提供可选参数的对象组成。 如果它们中的任何一个提供非空值,则获胜。
// calling code public Optional<Widget> getAppropriateWidget(CustomerRequest request) { return firstAvailable(() -> getShelfWidget(request), () -> getBackroomWidget(request), () -> getSupplierWidget(request)); } // this is a general purpose solution // feel free to use it @SafeVarargs private static <T> Optional<T> firstAvailable( Supplier<Optional<T>> ... options) { return Arrays.stream(options) .map(Supplier::get) .filter(Optional::isPresent) .findFirst() .orElse(Optional.empty()); }
翻译自: https://www.javacodegeeks.com/2019/11/first-past-the-post.html