强键入真的需要吗?


这是我最近几个月一直在纠结的事情。我曾有一些人热烈地争辩说,所有强打字都是有益的,但却是虚假的舒适和大量不必要的打字。但我很坚强。我没有被吓倒。我对此不屑一顾,认为这是那些JS开发人员的疯狂咆哮,那些相信模糊化和紧凑性就是一切的动态语言人员,甚至不惜以可维护性为代价。我的意思是,一种你甚至不知道以任何方式传递什么的语言怎么能比API显式的语言更好,并且阻止你犯错误。动态语言可以适用于单个开发人员,但绝对不适用于团队。这是我发自内心的结论。

现在,我再也不确定了。自从我们的团队做出全身心的转变以来,已经有三个星期了。是玫瑰和阳光吗?没有,但没有我想象的那么糟。这有几个原因。但在此之前,我将根据我的经验(当然是非常有限的)来阐述它们的利弊

强类型的好处:

  1. 编辑器中的错误/警告
    简单地说,这可能是强类型的最大好处,也是大多数java开发人员(这是非常正确的)永远不会考虑离开强类型安全的唯一原因。虽然编译支持不一定与强类型同步进行,但大多数人倾向于将Java与之联系起来,所以让我们使用它来运行。简单地说,使用强键入,您的编辑器可以(而且应该,我的意思是,如果您不打算获得IMMD.反馈,那有什么意义?)当你把事情搞砸时,立即给你反馈。不管这是使用了错误的变量名,还是试图调用一个不存在的方法或者使用了错误的参数。或者试图使用错误类型的对象。

    对于Java开发人员来说,像Eclipse或IntelliJ这样的IDE是天赐良机,因为它告诉您世界中的错误并允许您跳转到它们,给您提供建议和自动修复,并且通常使您的生活尽可能地无痛苦。我可以告诉你,这很棒。

    在Javascript(或任何其他动态语言)中,前100行都很好。在那之后,它就变得可怕地不可收拾。到目前为止,我发现的唯一解决这个问题的方法就是超级偏执,为每一行代码编写测试。如果你做不到,那就离得远远的。

  2. 泛型(但在我看来,这也是一个负面的问题,我将在下面讨论这一点)
    泛型背后的思想是为开发人员提供了一些关于集合中类型的保证(或您正在进行泛型的任何类型)。这样,所有操作都是类型安全的,而不必转换到不同类型或从不同类型转换。并且您可以确信,在您最不期望的时候,您不会突然被一个不同类型的对象弹出而感到惊讶。但是我将在第二节中讨论与它们有关的许多问题。
  3. 能够跟踪一条链,并计算出每一步所需的对象类型
    这是我在Javascript和Python等语言中绝对怀念的东西。我可以跟踪(在我的IDE中,请注意这一部分)表达式链中每个变量/方法调用的类型这一事实简直令人惊讶,尤其是当您使用新的代码库时。您永远不必想知道您正在调用的方法的参数类型是什么。您不必想知道哪些方法是可用的或可见的。您只是知道这些信息(再次强调,假设您正在使用IDE.如果不是,上帝保佑您)
  4. 重构

    在我看来,强类型的最大优势是创建IDE的能力,这使得重构变得轻而易举。重命名方法/变量?微不足道。移动还是提取方法?简单的组合键。一些非常乏味和麻木的事情在几分钟内就完成了。(想了解更多关于这些快捷方式的信息?请查看Eclipse快捷方式)。这在Python和JavaScript等语言中是不可能的。

强类型的缺点:
  1. 更简洁精确,少打字
    动态语言确实倾向于更密集,用10行代码就可以轻松完成像Java这样非常冗长的语言中需要50-100行代码的任务,这要容易得多。考虑尝试在Java和javascript中传递要在函数末尾执行的代码块(这在web应用程序和任务运行程序中非常常见)
    Java:
    interface Function {
    T execute(); // Optional parameters is not easy here :(
    }
    taskRunner.execute(taskArgument, new Function() {
    String execute() {
    return "Success";
    }
    });

    JavaScript

    taskRunner.execute(params, function() {response="Success"});
  2. 没有错误实现的泛型

    这主要是Java的错误,因为它把泛型搞错了。泛型背后的思想是合理的,但它的实现却被严重破坏了。以下是它的几个问题:
    类型擦除:这基本上涉及到这样一个事实,即在运行时,没有办法区分List<string>和List<integer>。如果您从不使用反射或Guice,那么这可能不是问题。但它也是一个深嵌套泛型和通配符的痛苦。我见过编译代码时会因为无法区分提供者<?扩展repository>和provider<?extends Resource>和Resource和Repository都没有任何共同之处。疯狂……。

    冗长:map<string,list<string>>myMap=new hashmap<string,list<string>>();。恩努夫说。

    Guice反射(&R):泛型和java.lang.reflect不能混合。他们就是不知道。类型擦除会删除所有类型信息,因此您肯定会使用像new Entity<?>这样的东西,这完全违背了目的。别让我从Guice开始。在guice中,普通绑定(非泛型类)如下所示:

    绑定(MyInterface.class)。ToInstance(实例);

    在涉及泛型的情况下,它们现在看起来如下所示:

    绑定(新的TypeLiteral<MyInterface<String>>(){})。ToInstance(实例);

    刚才到底发生了什么???

  3. 闭包/函数:
    闭包是匿名内部函数的一种形式,它可以有自己的环境,包括绑定到函数范围的变量。内部函数可以访问外部作用域的局部变量,并且可以改变状态。但它确实允许创建函数,作为回调或以重复的方式执行一些快速的小任务,这些函数既简单又快速,而且非常便宜。Java已经提出了一些添加它的建议(http://javac.info/),但它还没有通过审查委员会。未来几年可能不会。因此,在此之前,在Java中,您一直在创建接口,在运行时创建接口的实现,在构造函数中或通过其他机制传递需要访问的变量,并且通常处于非常痛苦的状态。谢谢,但不用了,谢谢。
发件人http://theshyam.com