elm';s编译不同于Java';是否检查异常?

elm';s编译不同于Java';是否检查异常?,java,elm,checked-exceptions,Java,Elm,Checked Exceptions,elm的索赔是其主要卖点之一(见) 但是如果你停下来想一想,没有什么能阻止你被零除或者耗尽内存 elm编译器的基本功能是强制您覆盖所有可能导致异常的路径 例如: import String exposing (toInt) toIntOrZero s = case toInt s of Err e -> 0 Ok val -> val 但是这与java中的“检查异常”功能有什么不

elm
的索赔是其主要卖点之一(见)

但是如果你停下来想一想,没有什么能阻止你被零除或者耗尽内存

elm
编译器的基本功能是强制您覆盖所有可能导致异常的路径

例如:

import String exposing (toInt)
toIntOrZero s = case toInt s of
                          Err e -> 0
                          Ok val -> val
但是这与
java
中的“检查异常”功能有什么不同呢

public static Integer toIntOrZero(String s) {
    try { return Integer.valueOf(s); }
    catch (NumberFormatException e) { return 0; }
}

我从来没有听说过有人声称
java
是一种零运行时异常语言。

请不要过于沉迷于本质上的营销夸张。当然,有些类错误是任何编译器都无法完全排除的

因此,我一直对这些零运行时异常声明持保留态度,但我认为我理解支持者的意图。Elm是作为Javascript开发前端应用程序的替代品而创建的,Javascript是一个混乱的世界,例外情况比比皆是,只是日常生活的一部分。Elm会让你更难自食其力,而且如果你在应用程序上运行基本的健全性测试,你可能永远不会在生产中出现运行时异常

Elm从几个方面大大降低了异常的可能性

  • 除了
    Debug.crash
    ,该语言中没有可丢弃异常的概念,顾名思义,它实际上应该只用于调试和清除不完整的逻辑路径

    由于没有可丢弃的异常,因此处理问题通常是通过
    Result
    Maybe
    等类型完成的

    这可以被认为是对Java的检查异常的松散分析,但从概念上讲,它们与我感觉非常不同。让我们面对现实吧。例外情况被滥用。您提到了Java中的一个示例,其中
    Integer.valueOf()
    表示它将返回一个int,但如果您传递其他任何内容,它将展开堆栈并冒泡,直到某个函数有望捕获它。这让我感觉非常混乱,当然,检查过的异常可以帮助减少故障传播的窗口,但潜在的事实是,异常对于业务逻辑来说是错误的工具

    抛出异常的另一种方法是让类与
    结果
    可能
    Elm类型相关联,但在Java早期,这几乎不可能做到干净,即使使用泛型,编写此类类型也比Elm类型的简单性更繁琐,更容易出错。由于Elm的封闭式系统

  • 非穷举模式匹配会导致编译失败

    在Java和Javascript中,无法进行彻底的模式匹配检查,因为类型系统不允许这样做。当然,Typescript引入了一些功能,但您必须选择它。在Elm中,必须显式处理所有情况。当然,我想你可能会争辩说Elm让你通过用catch-all
    \uuu
    结束所有case语句来选择不进行穷举模式匹配,但那只是对语言的愚蠢滥用。这些检查是为了帮助您,我觉得更安全的事实是,我没有选择在Elm中进行错误检查-默认情况下它就在那里

  • 不变性

    不变性避免了大量潜在的错误,这些错误太多了,无法在这里讨论

  • Elm体系结构在Javascript和Elm之间提供了清晰的分离

    Elm可以编译成Javascript,但是Elm架构提供了一个很好的干净屏障,可以让Javascript的所有讨厌的部分远离Elm编写的纯代码。Javascript中可能发生的任何异常都应该由该屏障处理,这样I/O错误将始终转换为Elm友好的无异常类型


  • 最后,运行时异常仍然是可能的(例如:处理由递归JSON解码器定义引起的众所周知的运行时异常),每当我听到有人说不可能在Elm中获得异常时,我都会有些畏缩。事实上,异常是可能的,但在日常Javascript开发中遇到的几乎所有异常在Elm中都是不可能的。

    正如一位评论员所指出的,Java有未经检查的异常,因此运行时错误确实会发生。Elm也有未经检查的例外情况,比如被零除,但去掉了在实践中最常见的例外情况。正如Chad的回答所提到的,Elm的
    可能
    /
    结果
    类型在实践中的工作方式与Java的检查异常非常不同。一个有经验的Elm程序员不会编写像
    toIntOrZero
    这样的函数(如果编写了,他们可能不会使用
    case…of
    ,而是更喜欢像
    toIntOrZero=String.toInt>>Result.with default 0

    将多个操作与
    Result.map
    Result.和
    等链接在一起,提供了一种非常有表现力的方法来处理错误案例,而不必强迫程序员深陷其中。例如,如果我们想编写一个函数,通过将ID转换为Int来验证ID,在某些数据结构中查找它(当它可能不存在时),然后验证与该用户关联的某些属性,我们可以编写如下内容:

    lookupUser : Int -> Result String User
    lookupUser intId = ...
    
    userInGoodStanding : User -> Bool
    userInGoodStanding user = ...
    
    isValidId : String -> Bool
    isValidId id = 
      String.toInt id 
      |> Result.andThen lookupUser 
      |> Result.map userInGoodStanding
      |> Result.withDefault False
    

    这是这样写的,“将ID转换为int,然后查找相关的用户,然后验证用户,如果有任何失败,则返回False。”您的里程可能会有所不同,但一旦您习惯了它,我(我想还有许多Elm程序员!)会发现这是一种非常好的编写代码的方法,对错误具有鲁棒性。

    Java仍然存在未检查的异常。充其量你可以说Java“具有成为零运行时异常语言的能力。公平的观点是,
    elm
    是一种