我写这篇很长的文章是对文章"为什么Java即将死去"的回应。我对此文本的评论名列前茅,我觉得我必须做出一个完全反对的声明,这应该返回平衡。
对于作者的尝试,最好的简短答案是Coder:76的答案,它获得了数百次鼓掌:
"在过去的15年中,Java对那些希望引起关注的编程博客作者来说已经死了。" |
很难不同意。
" Java快死了"的说法有什么问题?
"为什么Java即将死去"的文章收到了70多个评论,其中大多数是关键评论,每个评论都有成千上万的掌声。为什么这么多人做出如此消极的反应?原因看起来很简单:该文章以挑衅的方式撰写,包含许多有争议的陈述,对于使用Java的人来说,这些陈述远非现实。让我们来看看其中的一些。
"例如,在这里,Spring可以在后台设置自动装配(bean注入),这是可以理解的,但是Lombok在应用程序上下文中的位置又是如何在两者之间协调消息传递的呢?" |
对于使用上述技术的人们来说,这种说法是错误的。Lombok是一个编译时库,而Spring是一个运行时库。它们在应用程序生命周期的不同时间以不同级别工作,并且不直接交互。对于作者的问题" Lombok在应用程序上下文中住哪儿?"的正确答案。是"没有"。
" Java的重点似乎仍然是愚蠢的规则,这些规则规定了应使用的类名,应使用的包以及变量是私有的还是受保护的。说真的,谁在乎?" |
从事大型,长期项目的人会照顾他们。这些规则对他们来说并不愚蠢。
"相比之下,'我们都在这里成年'实际上是Python对该语言中缺少访问说明的官方回应。" |
毫无疑问,团队中的某人会认为其他人不是成年人,这是一个浅薄的主意。问题在于,由大型团队创建的,持续时间很长的大型项目需要规则。否则,它们将失败。大型项目就像一座大城市:它需要建筑基础,规划,关注点分离,私有和公共区域。如果熟练的程序员将语言结构分为公共结构和私有结构,则他们很可能会创建"街道",以正确的方式领导其他人,从而节省时间,并将辅助基础设施隐藏在"地下",以至于没有人迷路。
"为什么Java即将死去"一文中还有很多争议性的陈述,但是我的目的不是详细分析。我想做的是利用这次机会来谈论Java本身的现代状态。
多年来,Java是编程语言中的首选,同时也是批评家的首选。不是因为它不好,而是因为它是一件大事,如果想看起来比实际的大,必须说出反对某件大事的字眼,并祈求有人注意。从这个意义上讲,Java是一个很好的目标。但是现在呢?Java是否仍然是一件大事,还是像某些人所说的那样"濒死"?让我们讨论最重要且值得商榷的主题,以便找出答案。
语法
> Image by Harry Fabel from Pixabay
Java的语法通常被批评最多:"不够简洁","不适合现代任务","太多样板"等。对这些"参数"的唯一正确答案是显示代码。我将不在这里讨论特殊的语法功能。有很多详细的指南,涵盖了Java语法的所有细微差别。相反,我仅选择了五个代码片段供您了解现代Java如何针对不同的实际任务进行操作。
- import static spark.Spark.*;
- public class HelloWorld {
- public static void main(String[] args) {
- port(80);
- get("/hello", (request, response) -> "Hello World");
- }
- }
上述代码使用HTTP GET方法和/ hello上下文路径在端口80上使用Spark Java启动一个简单的Web服务器,当请求时该上下文路径将返回常量字符串。非常简单明了,不是吗?
- ...
- OrderRepository orders;
- QOrder qorder = QOrder.order;
- DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
- public Iterable<Order> getShopOrdersByDate(ShopId id, ZonedDateTime date){
- return orders.findAll(
- qorder.shopId.eq(id).and(qorder.date.eq(yyyyMMdd.format(date)))
- );
- }
- ...
上述代码结合使用Querydsl和Spring Data从SQL数据库中获取信息。一切看起来都非常简单:方法getShopOrdersByDate返回具有特定日期和特定日期格式的特定商店的订单。有趣的部分:这里没有SQL,只有Java构造,以后会在库中将其转换为安全的SQL。这意味着查询本身是类型安全的,并且在编译时(而不是在运行时中)被可靠地检查。而且,IDE可以像其他Java代码一样帮助您完成自动补全,使您的生活更轻松。开箱即用地支持大量数据库,例如PostgreSQL,MySQL,Oracle甚至MongoDB。另外,如果要交换查询代码,则无需更改查询代码。
- import java.nio.file.Files;
- import java.util.stream.Stream;
- import static java.nio.file.Paths.get;
- import static java.util.stream.Collectors.*;
- public class Example {
- public static void main(String[] args) throws Exception {
- List<String> fileLines = Files.readAllLines(get("huge.txt"));
- String fileStats = fileLines.parallelStream()
- .flatMap(line -> Stream.of(line.split("\\s+")))
- .filter(word -> !"dumb".equalsIgnoreCase(word))
- .collect(groupingBy(word -> word.charAt(0), counting()))
- .entrySet().parallelStream()
- .map(letterStats -> letterStats.getKey() + ":" + letterStats.getValue())
- .collect(joining("\n"));
- System.out.println(fileStats);
- }
- }
这里没有其他库,只有纯Java。从巨大的文件中读取所有行,将其分成单独的单词,过滤出哑词以保持所有内容的清洁,将单词按第一个字母分组,计算每个组中的单词数,创建结果组的字符串表示形式并进行计数,打印结果。可读性强且易于维护。当然,所有事情都是在并行线程中完成的,以便于开箱即用地进行适当的加速,以便您的新16核怪物可以证明其成本合理。在里面装有Java 15的4核笔记本电脑上,此代码平均需要6秒钟才能对填充有随机单词的1.2 Gb文本文件执行。对于这种文件大小和直接的未经优化的代码来说还不错。
- ...
- public MultiLayerNetwork createModel() {
- return new MultiLayerNetwork(new NeuralNetConfiguration.Builder()
- .regularization(true).l2(0.001)
- .learningRate(0.01)
- .weightInit(WeightInit.XAVIER)
- .activation(Activation.RELU)
- .optimizationAlgo(STOCHASTIC_GRADIENT_DESCENT)
- .updater(new Nesterovs(0.9))
- .list()
- .layer(convolution(5, 25).nIn(3).build())
- .layer(maxPooling(2).build())
- .layer(convolution(3, 50).build())
- .layer(maxPooling(2).build())
- .layer(convolution(3, 100).build())
- .layer(maxPooling(2).build())
- .layer(dense(200).dropOut(0.5).build())
- .layer(dense(200).dropOut(0.5).build())
- .layer(outputClassification(10))
- .setInputType(convolutionalFlat(28, 28, 3))
- .backprop(true).pretrain(false)
- .build());
- }
- ConvolutionLayer.Builder convolution(int filterSize, int filterCount) {
- return new ConvolutionLayer.Builder(filterSize, filterSize)
- .activation(IDENTITY).nOut(filterCount);
- }
- SubsamplingLayer.Builder maxPooling(int size) {
- return new SubsamplingLayer.Builder(PoolingType.MAX)
- .kernelSize(size, size).stride(size, size);
- }
- DenseLayer.Builder dense(int size) {
- return new DenseLayer.Builder().nOut(size);
- }
- OutputLayer outputClassification(int numOfClasses) {
- return new OutputLayer.Builder(LossFunction.MCXENT)
- .nOut(numOfClasses).activation(SOFTMAX).build();
- }
- ...
这个简单的示例显示了在学习阶段之前使用Dl4j准备神经网络结构的阶段。那些处于深度学习领域的人将轻松识别许多熟悉的单词。没什么特别的。是的,您通常可以使用Java进行深度学习和机器学习。
- import lombok.AllArgsConstructor;
- import lombok.Data;
- @Data
- @AllArgsConstructor
- public class User {
- String name;
- String surName;
- List<ContactInfo> contacts;
- }
你讨厌样板吗?然后使用lombok。此代码片段显示了功能齐全的数据类,其中正确完成的所有字段上均具有getter,setter,equals,hashcode,toString,最后是AllArgsConstructor。如果愿意,您当然可以覆盖其中的任何一个。
来自Java生态系统外部的人们通常会争辩说" Lombok使Java不是Java。"我不同意:Lombok是Java。它是现代Java生态系统的一部分,使用合法的Java机制来添加其功能,可以帮助您处理几乎零缺点的Java代码,并且受到许多Java开发人员的喜爱。多少?最流行的Java IDE之一将Lombok插件下载数量估计为11+百万。许多。这是一种使Java更好的工具,因此从实际意义上讲,它是数百万使用Java的人的Java。不过,Java社区中有一部分人反对Lombok,他们拥有这样做的全部权利-如果您不喜欢Lombok,则没有人会强迫您这样做。
现在想象一下这些示例在其他语言中的外观。您可能会发现用于达成相同目标的语言所包含的字符要少一些。但是,该代码是否会像Java语言一样可靠,可读性,可维护性和快速性?我几乎不这么认为。
与语法相关的另一重要事项是IDE支持。这不是抽象的理论问题,例如语言结构的强大程度或开发人员必须编写多少符号才能执行某项操作。 IDE添加了一个实用层,将所有抽象问题转换为一个问题:特定任务将花费多少开发人员时间。将精心设计的语言与现代IDE结合使用,与使用功能更强大或更简洁但对IDE友好程度更低的语言相比,开发人员可以更快地达到目标。 Java具有以下语法,这是Java最好的IDE支持之一:它不太复杂,同时也不太自由选择,因此IDE可以了解您当前正在使用的上下文并预测您想做什么。接下来非常精确。最后要说的是,Java的语法允许使用不同的编程样式。您的代码可以用面向对象的范例编写,其中对象彼此交互。在程序范式中,命令式程序调用的顺序改变了全局状态;或在功能范式中,您可以组合和应用功能以实现目标。有时人们会区分更多的范例-例如,Java非常适合面向方面或基于参与者的范例。 Java为您提供了极大的灵活性,使您可以思考自己的任务,因此它为应对周期性发生的编程范式时尚转变做好了充分的准备。
综上所述,Java的语法没有问题。它相对简单,灵活且富有表现力。此外,它还允许IDE通过多种方式有效地帮助开发人员,从而大大提高了他们的生产率。如果您精通Java,编写清晰的代码,并使用正确的工具集来完成任务,那么您的程序将是美观,可维护和简洁的。不要让人们在这个话题上欺骗您。
保证
> Photo by Joshua Hoehne on Unsplash
与许多其他技术不同,Java作为一种语言和平台为您提供了许多可以依赖的保证。
Java语言具有Java语言规范,这是对Java代码的构造应该如何工作和应该如何使用的主要判断。它为什么如此重要?因为您可以验证自己的工作并以严格,可预测的方式解决问题或纠纷。对于没有规范的语言,您不太确定会发生什么情况:您可能会在手册,博客或语言创建者的推文中找到一些信息,但是直到语言获得规范,所有这些信息才具备保证一切的坚实基础。
当然,规范可能具有不同的质量或不同的详细程度,因此可能会遗漏某些内容。尽管如此,具有规范的语言比没有语言的语言给您提供了更高的信心,使您确信自己在做正确的事情。Java的规范非常深入和详细,几乎没有歧义。
Java版本对规范和公共Java API中的内容具有强烈的向后兼容性。这意味着,如果您使用使用20年前编写的版本1.3的公共Java API的代码,并且今天在Java 15上运行它,它将可以正常工作。同时,如果您使用私有Java API,该API由不应由开发人员直接使用的类和方法/字段组成,则可能会遇到麻烦。我认为这很合理:如果您使用可以保证向后兼容的产品,则可以依靠它,但是如果您使用了不打算使用的产品,请不要期望它们永远有效。
Java是安全可靠的-并非绝对如此;实际上。Java代码是安全的,因为与许多其他语言相比,开发人员使用Java代码出错的可能性较小。从Java代码不能直接访问操作系统或硬件的角度来看,这是安全的,因此Java运行时可以安全地限制Java程序可以做什么和不能做什么。
Java代码是可移植的。这意味着您可以在一个平台上编译Java代码,并且可以在实现Java虚拟机的任何平台上运行它,而无需重新编译。"编写一次,随处运行" –古老的Java标语,直到25年后的今天仍然可行。广泛的可移植性以及向后兼容性是保证的非常强的组合,这使开发人员确信他们的努力和知识不会很快过时。当然,在某些特殊情况下,由于诸如硬件限制之类的各种原因,某些虚拟机仅允许Java语言规范的子集。例如,您可以在8kB RAM微控制器上运行Java代码,但是必须考虑一些限制。
Java代码是可维护的。与C ++之类的语言相比,Java的语法非常简化。它缺乏C ++具有的许多功能,自定义项和强大的构造。同时,与脚本语言相比,Java具有许多乍一看都是多余的"仪式"。从这个意义上讲,Java试图在复杂性,功能和可读性之间保持平衡,以最大化长期代码可维护性。什么是可维护性?我将其描述为普通技术开发人员将更改应用于现有代码库(可能是旧代码库)所需的时间,这可以达到开发人员的目标,并且不会破坏其他任何东西。所需时间越短,可维护性就越高。
从这个意义上讲,Java是好的。一方面,它功能强大,足以表达开发人员所需的许多内容,但同时又不像语言那样复杂,人们可以使用极其强大的语言构造(只能由其创建者理解)来创建精美,无法解决的迷宫。另一方面,Java要求开发人员编写比开发人员通常用脚本语言编写的更详尽的代码,并且编写更明确的内容,以提高可读性并易于理解时间流逝后发生的事情。
Java很快。如果您尝试研究此主题,可能会发现许多文章,例如" Java比X快"和" X比Java快",其中包含矛盾的陈述和结论。如果您尝试进行实验,则可以轻松地构造Java速度慢而Java快速发展的示例-顺便说一句,您可以使用其他语言来完成相同的技巧。关于为什么过去认为Java速度很慢有很好的评论。现在有点过时了。例如,最新的Java运行时中的字符串处理要比七年前好得多,而且我也不同意其他一些声明。但是总的结论是,对于每个发行版,Java都会进行优化以提高其性能。还记得本文"语法"部分的第三个示例,其中处理了巨大的1.2 Gb文件?使用Java 8,在我的笔记本上平均要花十秒钟,而使用Java 15,只有相同配置的六秒钟。这是该语言的开发人员为我们提供的重要保证之一:Java足够快,足以应付当今的许多任务,并且将来会更快。
关于担保的最后一件事要说的是:它们已经实现了25年以上,并且没有理由在未来的几年中不会实现。
Java缓慢实现现代语言功能
> Photo by Makarios Tang on Unsplash
是。通常,慢是一件坏事吗?不。问自己以下。如果您骑着自行车,偶尔看到前方的墙壁,您会喜欢什么:加速还是减速?我打赌你选择和我一样。
那么,为什么Java采用的功能比其他某些语言的速度慢?由于担保,我们在上一节中讨论过。这些保证就是一堵墙,它迫使对功能进行仔细地讨论,过滤或以某种方式进行变换,在这里,慢是比着急更好的朋友。关于如何将更改应用于Java语言的正式过程称为Java社区过程。此过程的主要目的是验证所提出的功能不会破坏保证。有时候,这并不是一项显而易见且快速的任务。
Java语言的开发人员试图在创新和保证之间保持平衡,这比"让我们现在将这种很酷的功能添加到我们的语言中"要难得多。但是,从长远来看,它可以带来更多利润,因为保证意味着信任,这对未来来说比有价值的功能集更有价值。Brian Goetz讨论了Java的这种策略和总体哲学。请看一看。
另外,值得一提的是当前的Java发布时间表。9月和3月每六个月发布一次Java的新版本,该版本完全可以使用,并在接下来的六个月中逐步更新。每三年,其中一个这样的版本将成为长期支持(LTS)版本,并在接下来的三年中逐步更新。现在,Java 15是最新版本,而Java 11是当前的LTS。LTS的下一个发行版将是Java 17,计划于2021年9月发布。每个版本都可以包含许多"预览功能",对于这些功能,不能保证将来的发行版具有兼容性。他们的目标是为开发人员提供尝试有争议的创新并留下反馈的可能性。如果某个功能未标记为预览,则表示该功能已完全包含在平台中,并将具有Java提供的所有保证。
生态系统
> Photo by Greg Rakozy on Unsplash
有些人狭义地理解语言生态系统,仅将其概念限制为程序员可以使用的一组库。我更倾向于将生态系统视为解决问题的工具。开发人员可以用该语言解决的问题越多,其生态系统就越广泛。优先选择哪个含义都没有关系:Java具有庞大的生态系统。
这是我之前问自己解决我遇到的问题的个人随机问题列表:
- 我可以使用对HTML,JS和CSS零知识的纯Java编写Web应用程序吗?是。
- 我可以在毫秒级的世界范围内使用TB级的堆吗?是的,很容易。
- 我可以用纯Java处理图像和视频以实现可移植性吗?是。
- 我可以使用Java进行深度学习吗?是的,请。
- 我可以使用Java对在黑色星期五购买的机器人进行编程吗?是。
- 我可以找到有关Java的随机愚蠢问题的答案吗?是。
该列表绝对是个人的,但是我可以肯定,在大多数情况下,当问题在编程环境中并且涉及Java时,"是"的实例将压倒"否"的实例。
在Java生态系统的帮助下,您可以解决许多领域中的许多问题,此外,通常您也有多种选择方式。如果您想了解Java生态系统的广阔程度,请查看此资源。
启动时间和内存占用量
> Photo by Bill Oxford on Unsplash
Java代码被编译为称为Java字节码的中间形式,然后在称为JVM的运行时平台上执行。除了抱怨Java语法外,评论家通常还会抱怨JVM内存占用量和启动时间。让我们更详细地讨论。
JVM代表Java虚拟机,这意味着您的应用程序由虚拟计算机在沙箱中运行。这种方法有很多好处。开发人员无需考虑运行应用程序的操作系统和硬件的细微差别。虚拟沙箱提供了更高的安全性,因为它不允许应用直接与低级事物进行交互。虚拟环境位于您的应用程序外部,可以动态优化它,以提高在不同情况下的性能等。
缺点是JVM需要额外的资源(包括内存和处理器时间)才能运行,并且具有启动和预热时间。
在通常的使用情况下,根据应用程序的不同,标准的Oracle HotSpot JVM会引入数十或数百兆字节的额外空间,平均需要几秒钟的启动时间。(JVM本身通常在不到一秒钟的时间内启动,但是其他一些库由于其内部例程而增加了该时间。)而且,在启动后的最初几秒钟内,JVM可以消耗比平均更多的CPU,因为它可以识别并编译"字节码中的"热门"部分以优化其将来的用法。
在大多数情况下,这些缺点对于许多类型的应用都是合理的。但是在某些情况下,它们并非如此,您希望以某种方式权衡利弊。那你该怎么办?您是否应该放弃Java而改用其他东西?通常不会-仅选择另一个适合您特定任务的运行时。
考虑例如微服务域。现代微服务应用程序通常需要最少的内存占用空间和启动时间,以有效地填充Kubernetes等容器编排器。为了满足这一需求,Java开发人员创建了GraalVM。它允许开发人员从Java代码创建本机映像,这些映像将在数十毫秒的启动时间和仅几兆字节的额外内存占用下运行。许多Java Web框架使GraalVM适应微服务领域:Quarkus,Micronaut,Spring和Helidon。
交易弊端?您将失去可移植性,并且生成的映像只能在GraalVM为其编译的平台上运行。但是对于微服务而言,这并不是很重要,因为您的应用很可能会在具有预定义环境的容器中运行。您可能还会面临其他一些限制。无论如何,当您听到Java不适合现代微服务需求时,请记住:该陈述是错误的。
正如许多批评家所说,Java并不意味着过度使用内存和缩短启动时间。内存使用情况和启动时间主要取决于最终运行应用程序所用的运行时以及所使用的其他库。从这个意义上讲,Java生态系统根据您的需求为您提供选择。
Java真正的目的是什么?
> Photo by Xavi Cabrera on Unsplash
Java可以用于您想像的一切:API和Web服务器,游戏和多媒体软件,UI和Web应用程序,IoT和机器人技术,AR和VR,机器学习和数据流,数据库和云原生微服务,大型企业系统和小原型。有没有排除事项?技术上不,实际上是。Java并不是低级系统语言,因此用Java创建操作系统或硬件驱动程序的核心不是一个好主意。从技术上讲是可能的,但是针对这些情况,有比Java更好的工具。
但是我们必须为Java付费,对吧?
> Photo by Jp Valery on Unsplash
不,如果您使用免费的Java发行版,则不必为Java付费。Java是开源的,因此任何人都可以构建现成的Java发行版,并且有许多免费的预构建发行版,例如OpenJDK,AdoptOpenJDK,AWS Coretto,Azul Zulu等。这些发行版的使用是绝对免费的,并且它们中的任何一个极有可能满足您的要求。如果您想了解更多有关此信息,请参阅本文。
Java的未来
> Photo by Karsten Würth on Unsplash
总结一切:Java仍然是一个很重要的语言。
它的作用是成为许多领域的核心技术,在创新,功能和可维护性之间取得平衡,以可持续地支持所使用的项目。如果您想尝试新颖的语言构想,请选择另一种技术。但是,如果您看到某个特定功能最终找到了它成为Java规范的方式,则可以确定不是由于偶然的情况或很小的时尚波动而添加了该功能,而是经过深入研究和为达到相同水平而付出的巨大努力设计的结果保证其他Java功能具有。从这个意义上讲,您可以信任Java,这与市场上的许多其他技术不同。
如果您在问初学或初学时应该学习哪种计算机语言,只需尝试一下Java。我敢肯定Java将在我们身边住很长时间。
我敢打赌,关于Java为什么会长寿,本文还遗漏了许多其他好的论点,欢迎您在评论中分享它们。
原文链接:https://medium.com/better-programming/why-java-is-perfectly-alive-e3f25a576f95
【责任编辑:赵宁宁 TEL:(010)68476606】