- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
好吧,我是一个长期的 OO 开发人员,试图进入这个“新发现的”函数式编程世界 - 至少,因为它与此有关,我正在尝试像 null
和 throw
这样的代码通过玩弄 Option
和 Either
monads,在 Java 领域并不存在。 (至少,我认为它们是单子(monad);我仍然对这个术语感到不自在,无论我是否正确使用它……)我要离开 Atlassian Fugue 库;我试着查看 Functional Java 库,它比我现在准备的要大得多。如果 fj 满足了我的需求而 Fugue 没有,我完全赞成。
基本上,我要完成的工作相当于这个相当丑陋的 Java 代码:
InputObject input = blah();
try {
final String message = getMessage(input);
if (message != null) {
try {
final ProcessedMessage processedMessage = processMessage(message);
if (processedMessage != null) {
try {
final ProcessedDetails details = getDetails(notificationDetails);
if (details != null) {
try {
awesomeStuff(details);
} catch (AwesomeStuffException ase) {
doSomethingWithAwesomeStuffException(ase);
}
}
} catch (GetDetailsException gde) {
doSomethingWithGetDetailsException(gde);
}
}
} catch (ProcessMessageException pme) {
doSomethingWithProcessMessageException(pme);
}
}
} catch (GetMessageException gme) {
doSomethingWithGetMessageException(gme);
}
天真地,使用 Either
monad,我期望能够做这样的事情:
getMessage(input).fold(this::doSomethingWithGetMessageException, this::processMessage)
.fold(this::doSomethingWithProcessMessageException, this::getDetails)
.fold(this::doSomethingWithGetDetailsException, this::awesomeStuff)
.foldLeft(this::doSomethingWithAwesomeStuffException);
...其中每个逻辑方法都将返回一个 Either,其中包含适当的异常(可能是特定于域的错误类,但异常现在工作得很好)作为左侧,Option<something>
作为右侧. doSomethingWith...
方法将对错误执行他们想要执行的任何日志记录/处理。逻辑方法的一个例子是:
Either<GetMessageException, Option<String>> getMessage(final InputObject input) {
if (input == null) {
return Either.left(new GetMessageException("Input was null");
}
try {
return Either.right(loadMessage(input));
} catch (Exception ex) {
return Either.left(new GetMessageException(ex));
}
}
其他方法的定义类似;最好不要将 Option
作为参数 - 如果先前的方法返回 Option.none
,则该方法根本不会被调用。
除了让我无法实际测试它的泛型类型的编译器错误巢穴之外,从逻辑上讲它看起来并不像它实际上做我想做的事 - 我期望事情基本上没有操作在返回第一个 Either.left 值后,但仔细观察它我猜它会继续尝试将 Either.left 结果传递到下一个调用并继续进行下去。
我 was
仅使用选项就可以实现我的目标:
getMessage(input).map(this::processMessage)
.map(this::getDetails)
.map(this::awesomeStuff);
不幸的是,要完成与原始 block 相同的逻辑,逻辑方法将与此类似地实现:
ProcessedMessage processMessage(final String message) {
try {
return doProcessing(message);
} catch (Exception ex) {
final GetMessageException gme = new GetMessageException(ex);
doSomethingWithGetMessageException(gme);
return null;
}
}
由于 .map
将结果提升为 Option
,因此在此处返回 null
工作正常。不幸的是,我基本上仍然对调用者隐藏了错误状态(更糟糕的是,IMO 使用 null
来表示错误 - 这并没有说明 doProcessing 是否出于潜在的正当理由返回 null
)。
因此,从本质上讲,我喜欢具有与前面的 getMessage 示例一致的方法签名 -
Either<GetMessageException, Option<String>> getMessage(final InputObject input)
我喜欢这样的想法,即能够查看返回值并一眼就知道“此方法要么会失败,要么会返回一些可能存在但可能不存在的东西。”但是,我对 FP 太陌生了,不知道如何去做。
我的理解(尽管可能有缺陷)是我可以做类似的事情
getMessage(input).fold(this::doSomethingWithGetMessageException, this::processMessage)
.fold(this::doSomethingWithProcessMessageException, this::getDetails)
.fold(this::doSomethingWithGetDetailsException, this::awesomeStuff)
.foldLeft(this::doSomethingWithAwesomeStuffException);
(尽管可能使用不同的方法)将
doSomethingWithXException
方法并停止)doSomethingWithAwesomeStuffException
的调用失败时调用 awesomeStuff
- 如果任何其他方法失败,它将无法到达。我尝试做的事情是否合理?我的意思是,我确信这是可能的,但是尝试将其硬塞进 Java 语法中是否太复杂了,甚至使用这些库中的任何一个(或我不知道的其他库)?
最佳答案
这肯定是一个自以为是的问题。你想要的是 flatMap 也被称为 monad 的绑定(bind)运算符。不幸的是,并不是所有的功能库都这样做(即 Guava 在其 Optional 上没有 flatMap)。 RxJava和 Reactor确实支持这种类型的操作,但这需要让您的服务更像流(我强烈推荐)。
据说在 Java 中执行这种逻辑存在很多问题,即 Java 没有任何模式匹配或任何 variants/ADTs/case classes .
由于上述原因以及大多数序列化程序在通用容器(即 Jackson)方面存在问题,大多数时候一个好的方法是使用行为 free 不可变的唯一类来返回结果(通常是静态内联类).
我在服务中一直这样做。即创建特定于特定服务请求的内联静态类。您可能会实现接口(interface)以跨内联类重用算法行为,但现实是 Java 对元组/变体/ADT/案例类的支持很糟糕(见上文)。
这通常(但并非总是)比在经常丢失数据的情况下抛出异常要好。
关于java - 使用 Fugue/FunctionalJava 摆脱 Null 和 Throws?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37037867/
Windows 上是否有多 Node 和 Fugue 的替代方案?我能够安装多 Node ,但它无法在 Windows 上运行,因为它依赖于 process.bind("net") 并且我无法安装 f
好吧,我是一个长期的 OO 开发人员,试图进入这个“新发现的”函数式编程世界 - 至少,因为它与此有关,我正在尝试像 null 和 throw 这样的代码通过玩弄 Option 和 Either mo
我是一名优秀的程序员,十分优秀!