EA问题的JDK14实例

Tagir Valeev最近发布了一条有关即将发布的Java JDK14版本的预览功能的推文:

#Java14模式匹配将名称隐藏带入了更高的疯狂程度。 在这里,我为FLAG字段添加或删除了final修饰符,该修饰符仅在不可达的if分支中访问。 这实际上改变了程序的语义! #ProgrammingIsFun 。 pic.twitter.com/UToRY3mpW9

问题在于,有一个计划中的并且在EA版本中已经可用的Java新功能引入了模式变量,而所提议的新标准的当前版本为某些真正令人毛骨悚然的编码问题留出了空间。

鸣叫之后,对细节进行了足够详细的讨论,以了解实际问题。 但是,在本文中,我将总结所有这些内容,以使您无需深入了解推文和标准。

什么是模式变量

在上面的推文中深入探讨问题概述之前,让我们先讨论一下模式变量是什么。 (也许有点草率,比准确和完整更能说明问题,但是来了。)

进行多次编程后,我们需要检查某些对象的类型。 运算符instanceof为我们做到了。 典型的示例代码可以是这样的:

 // HOW THIS IS TODAY, JAVA < 14  Object z = "alma" ;  if (!(z instanceof String)){ throw new IllegalArgumentException();  }  System.out.println(((String)z).length()); 

在现实生活中,变量z可能来自其他地方,在这种情况下,它是不那么明显,这一个字符串。 当我们想使用println打印出字符串的长度时,我们已经知道z引用的对象是一个字符串。 另一方面,编译器则没有,我们必须将变量强制转换为String ,然后才能使用length()方法。 其他语言做得更好。 理想情况下,我可以写:

 // HOW IT WOULD BE THE SIMPLEST  Object z = "alma" ;  if (!(z instanceof String)){ throw new IllegalArgumentException();  }  System.out.println(z.length()); 

这不是Java方式,也不是JDK14简化此编程模式的方式。 相反,建议的功能为instanceof运算符引入了一种新语法,该语法引入了一个新变量: 模式变量

长话短说,上面的示例如下所示:

 // HOW IT IS IN JDK14-EA / OpenJDK (build 14-ea+28-1366)  Object z = "alma" ;  if (!(z instanceof String s)){ throw new IllegalArgumentException();  }  System.out.println(s.length()); 

它引入了一个新变量s ,仅当引用的对象是String时才在范围内。 没有异常抛出部分的简单代码版本是

 Object z = "alma" ;  if (z instanceof String s){ // we have here 's' and it is a String System.out.println(s.length());  }  // we do not have 's' here 

当条件为true时,对象是字符串,因此我们有's'。 如果条件为假,那么我们将跳过then_statement,并且由于没有字符串,所以这里没有's'。 代码中只有在对象为字符串时才运行“ s”。 这样,模式变量的变量范围不仅受变量的句法范围的限制,而且还受可能的控制流程的限制。 仅考虑可以确定分析的控制流。

在Java编译器中,这种控制流分析并非无与伦比。 例如,如果存在编译器可以检测到的无法访问的代码,则Java程序将不会编译。

到目前为止,这似乎很简单,我们都很高兴获得Java 14的新功能。

JSL14标准

精确的范围计算在JLS14(Java语言规范14)标准中定义。 在撰写本文时,该规范仅作为预览提供。

http://cr.openjdk.java.net/~gbierman/jep305/jep305-20191021/specs/patterns-instanceof-jls.html#jls-6.3.2.2

由于Java程序的执行流程可以由许多不同的语言构造来控制,因此为每种结构定义了模式变量的范围。 针对不同的逻辑运算符,有单独的部分来评估短路,“ if”语句,“ while”语句等。 我不想广泛讨论不同的情况。 在这里,我将仅关注“ if”语句的情况,而没有“ else”部分。 上面引用的标准说:

以下规则适用于“ if(e)S”(14.9.1)语句:

*当e为true时,由e引入的模式变量肯定与`S`相匹配。

如果`e`引入的任何模式变量true都已经在`S`的作用域内,则是编译时错误。

*当且仅当`false`和`S'无法正常完成时,`if(e)S`引入`V`。

如果`if`语句引入的任何模式变量已经在范围内,则是编译时错误。

有趣的部分是“无法正常完成”。 上面的示例就是一个很好的例子:我们创建了一个所谓的guard if语句。 当变量z不是String我们将抛出异常,返回或执行其他操作,这将始终阻止在变量不是Stringif语句之后执行代码。

对于throwreturn语句,通常很容易直接看出代码“无法正常完成”。 在无限循环的情况下,这并不总是那么明显。

问题

让我们看一下以下代码片段:

 private static boolean FLAG = true ;  static String variable = "Hello from field" ;  public static void main() { Object z = "Hello from pattern matching" ; if (!(z instanceof String variable)){ while (FLAG) { System.out.println( "We are in an endless loop" ); } } System.out.println(variable);  } 

在这种情况下,我们有一个循环,它是无限的或不是无限的。 这取决于代码的另一部分,这可能会将类字段FLAG的值从true更改为false 。 这部分代码“可以正常完成”。

如果我们修改上面的代码,只需稍微使字段FLAGfinal ,如

 private static final boolean FLAG = true ;  static String variable = "Hello from field" ;  public static void main() { Object z = "Hello from pattern matching" ; if (!(z instanceof String variable)){ while (FLAG) { System.out.println( "We are in an endless loop" ); } } System.out.println(variable);  } 

那么编译器将看到循环是无限的并且无法正常完成。 在第一种情况下,程序Hello from field中打印出Hello from field Hello from pattern matching打印Hello from pattern matching 。 第二种情况下的模式variable隐藏了字段variable因为模式变量的范围扩展到了if语句之后的命令,因为那么部分无法正常完成。

确实,此预览功能确实存在问题。 在这种情况下,代码的可读性非常可疑。 模式变量的范围以及是否隐藏字段取决于该字段的final修饰符,该修饰符不存在。 当我们查看某些代码时,实际的执行和代码结果应该很简单,并且不应真正依赖于距离很远的某些代码,并且可能会跳过我们在本地阅读代码的注意。

这不是Java中唯一出现此异常的情况。 例如,您的代码库中可以有一个名为String的类。 当它们引用String类型时,位于同一包中的类的代码将使用该类。 如果我们从用户代码中删除String类,则String类型的含义变为java.lang.String 。 该代码的实际含义取决于“远”的其他代码。

但是,第二个示例是一个黑客,没有失去主意的Java程序员不可能将String类命名为(严重https://github.com/verhas/jScriptBasic/blob/master/src/main/ java / com / scriptbasic / classification / String.java ?)或JDK中java.lang包中也存在的其他名称。 也许这是纯粹的运气,也许在决策过程中考虑到了避免从java.lang包中强制导入类的java.lang 。 这是历史。

另一方面,变量名隐藏和上面的情况似乎并不那么怪异,某些Java代码中肯定不会偶然发生某些事情。

幸运的是,这只是预览功能。 它将按原样出现在JDK14中,但是作为预览功能,仅当javac编译器和Java执行使用--enable-preview标志并且预览功能将来可能以不兼容的方式更改时,该功能才可用。

我不知道它将如何改变。 我什至不能说它会改变。 仅凭我个人的看法,如果仍然这样下去将是非常可悲的。 有了此功能,只要我们计算经验丰富的Java程序员可以编写的程序的精妙程度和可读性,Java就会是更好的语言。 但是,如果我们看看没有经验的,新鲜的初级人员如何弄糟代码,情况将会更糟。 以我的拙见,第二点更为重要,而Java在这方面有很强的优势。 Java不是一种黑客语言,您应该非常拼命编写一个非常不可读的代码。 我不希望它改变。

说完之后,我们可以看看技术上的可能性。 一种是放弃该功能,这实际上不是一个好的解决方案。 这实际上不是解决方案。

另一种可能性是将模式变量的范围限制为then语句或else语句。

这样,我们就不会依赖代码的“无法正常完成”功能。 else保证只有在if语句的条件为false时才执行else分支。 这将使解决方案不太优雅。

同样,另一种可能性是禁止模式变量遮盖任何字段变量。 它可以解决上面概述的问题,但是会引入一个不同的问题。 受此限制,当我们引入一个名为V的新字段变量时,可能会发生带有方法和模式变量V的现有类停止编译的情况。 至少此问题是编译时的问题,而不是运行时有问题的某些代码。

我宁愿有100个编译时错误,也不愿有1个运行时错误。

还有一种可能是放弃模式变量,而仅使用原始变量和扩展的类型信息,而当前的预览解决方案使用模式变量。 Kotlin粉丝会喜欢这种解决方案。 由于局部变量已经遮蔽(或不遮盖)字段变量,因此这也可以很好地消除阴影问题。 此解决方案的缺点是,重新作用域限定的变量类型在代码的不同位置将具有不同的类型。 让我们看下面的代码:

 package javax0.jdk14.instanceof0;  public class Sample2 { public static class A { public static void m(){ System.out.println( "A" ); } } public static class B extends A { public static void m(){ System.out.println( "B" ); } } public static void main(String[] args) { A a = new B(); if ( a B b){ ( a instanceof B b){ bm(); } am(); }  } 

此代码将先打印出B然后打印出A因为根据变量b的声明类型,对bm()的调用与Bm()相同,并且根据声明的类型,对am()Am()的相同方法的变量a 。 省略模式变量并使用原始变量可能会造成混淆:

 // NOT ACTUAL CODE public static void main(String[] args) { A a = new B(); if ( a B){ ( a instanceof B){ am(); } am(); } 

am()会在不同的行上调用不同的方法吗?

如您所见,没有已知的最佳或最佳解决方案……除了一个。 在JDK中称您的代表为“议会”,并告诉他们那样不好。 (Psst:他们已经从原始推文中知道了。)

带走

这是一篇特别的文章,因为这与某些完善的Java功能或某些良好的编程工具或样式,模式,方法无关。 我们讨论了预览功能。 预览功能也许证明了我们为什么需要Java中的预览功能。

对于需要长期支持的长期商业项目,请使用最新的LTS版本。

将最新发布的Java版本用于您的实验和开源项目,并在用户需要时准备支持较旧的Java版本。

不要在项目中使用预览功能,也不要准备从代码中获得新版本,以防它们在变为非预览但正常功能时在下一个Java版本中发生更改。

尝试使用预览功能以将其包含在内,并在它们成为真实功能时具有某种肌肉记忆。 并且还可以向Java社区提供反馈,以防您觉得它们不是很完美。

翻译自: https://www.javacodegeeks.com/2020/01/jdk14-instance-of-ea-issue.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/340985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python去除图像光照不均匀_CVPR 2020 | 从重建质量到感知质量:用于低光照增强的半监督学习方法...

CVPR 2020 | 从重建质量到感知质量&#xff1a;用于低光照增强的半监督学习方法Code: https://github.com/flyywh/CVPR-2020-Semi-Low-Light1背景本篇为大家介绍我们组被2020年IEEE国际计算机视觉与模式识别会议(CVPR 2020)接收的工作《From Fidelity to Perceptual Quality: A…

jpa 手动预编译_编译时检查JPA查询

jpa 手动预编译JPA提供了几种查询数据的方法。 可以根据各种标准&#xff08;例如&#xff0c;使用的语言&#xff08;SQL与JPQL&#xff09;或查询是静态的&#xff08;编译时间&#xff09;还是动态的&#xff08;执行时间&#xff09;&#xff09;对此类替代方案进行分类。 …

多层陶瓷电容器用处_【科普贴】多层陶瓷电容器的制造工序,你知道吗?

本文将向大家介绍多层陶瓷电容器的结构及制造工序。多层陶瓷电容器的基本结构电容器用于储存电荷&#xff0c;其最基本结构如图1所示&#xff0c;在2块电极板中间夹着介电体。图1. 电容器的基本结构电容器的性能指标也取决于能够储存电荷的多少。多层陶瓷电容器为了能够储存更多…

使用ORM提取数据很容易! 是吗?

介绍 几乎任何系统都以某种方式与外部数据存储一起运行。 在大多数情况下&#xff0c;它是一个关系数据库&#xff0c;并且数据获取通常委托给某些ORM实现。 ORM涵盖了很多例程&#xff0c;并带来了一些新的抽象作为回报。 Martin Fowler写了一篇有关ORM的有趣文章 &#xff0…

分段式多级离心泵_离心泵与多级离心泵工作原理

离心泵工作原理&#xff1a;离心泵工作时&#xff0c;液体注满泵壳&#xff0c;叶轮高速旋转&#xff0c;液体在离心力作用下产生高速度&#xff0c;高速液体经过逐渐扩大的泵壳通道&#xff0c;动压头转变为静压头。性能特点&#xff1a;高效节能&#xff1a;泵有高效的水力形…

java8 javafx_JavaFX技巧8:美丽深层

java8 javafx如果您正在开发JavaFX的UI框架&#xff0c;请养成一种习惯&#xff0c;始终将自定义控件拆分为控件类和外观类。 来自Swing自己&#xff0c;这对我来说并不明显。 Swing还使用MVC概念&#xff0c;并将实际的组件呈现委托给UI委托&#xff0c;但是扩展Swing的人们大…

牛客网数据开发题库_数据库刷题—牛客网(21-30)

21.查找所有员工自入职以来的薪水涨幅情况&#xff0c;给出员工编号emp_no以及其对应的薪水涨幅growth&#xff0c;并按照growth进行升序CREATE TABLE employees ( emp_no int(11) NOT NULL, birth_date date NOT NULL, first_name varchar(14) NOT NULL, last_name varchar(16…

弹性堆栈介绍

当您运行对公司至关重要的软件时&#xff0c;您将无法获得仅用于分析一段时间前发生的事情的日志&#xff0c;让客户端告诉您您的应用程序已损坏&#xff0c;而您甚至不知道发生了什么是真实的问题。 解决该问题的方法之一是使用监视和日志记录。 大多数应用程序都将具有日志记…

access统计没有选课的人数_当代大学生发愁求职就业,更发愁“选课”,自主选课变成了负担...

当代大学生除了求职就业&#xff0c;最发愁的就是“选课”。不得不说&#xff0c;随着科技的发展&#xff0c;各行各业都发生了翻天覆地的变化。而在大学里的选课&#xff0c;也因此有了巨大的改变。过去&#xff0c;大学生上课&#xff0c;其实课程都是被安排好的&#xff0c;…

产线数字化软件源码_品质笔记⑥丨卢宇聪:把握数字化趋势,坚定创新发展道路...

6天5夜&#xff0c;跨越3座城市&#xff0c;深度走访7家企业&#xff0c;对话多位企业家……这是一趟开阔视野之旅。我接触了很多之前极少有机会接触的企业&#xff0c;比如做光缆的法尔胜泓晟集团、做节能装备的双良集团、做密封件的天生密封件有限公司等。我以前经常接触的是…

es 安装kopf_Elasticsearch-kopf导览

es 安装kopf当我需要一个插件来显示Elasticsearch的集群状态时&#xff0c;或者需要深入了解通常为经典插件elasticsearch-head所达到的索引时。 由于有很多建议&#xff0c;而且似乎是非官方的继任者&#xff0c;所以我最近更详细地研究了elasticsearch-kopf 。 我喜欢它。 我…

会导致小程序onhide码 手机息屏_小程序onshow事件

问题描述onShow 事件在小程序里面非常重要&#xff0c;场景之多&#xff0c;导致处理起来很复杂。很多业务场景依赖与onShow与onHide事件。比如分享给他人&#xff0c;在群里PK等等。息屏&#xff0c;新页面返回、Home键操作&#xff0c;也会触发onShow事件。以下是官网的说明&…

Spring@主要注释

介绍&#xff1a; 当存在多个相同类型的bean时&#xff0c;使用Spring Primary批注为标记的bean提供更高的优先级。 默认情况下&#xff0c;Spring按类型自动连线。 因此&#xff0c;当Spring尝试自动装配并且有多个相同类型的bean时&#xff0c;我们将获得NoUniqueBeanDefini…

python帮助文档快捷键_Pycharm快捷键手册

AltEnter 自动添加包Ctrlt SVN更新Ctrlk SVN提交Ctrl / 注释(取消注释)选择的行CtrlShiftF 高级查找CtrlEnter 补全Shift Enter 开始新行TAB ShiftTAB 缩进/取消缩进所选择的行Ctrl Alt I 自动缩进行Ctrl Y 删除当前插入符所在的行Ctrl D 复制当前行、或者选择的块Ctrl …

arm 交叉编译找不到so_搭建交叉编译环境并验证

1. 搭建编译环境并验证1.1 实验目的 掌握嵌入式开发环境、交叉编译器的搭建、安装和配置方法 熟悉Linux应用程序的编译、调试方法&#xff0c;能够验证X86平台和ARM平台的差异1.2 实验内容 交叉编译器环境搭建 编写一个典型的Linux应用程序 使用GDB调试Linux程序(PC平台) 用Mak…

雷达的工作原理示意图_电磁阀的构成和工作原理示意图

电磁阀符号的含义&#xff1a;电磁阀符号由方框、箭头、“T”和字符构成。电磁阀图形符号的含义一般如下&#xff1a;1、用方框表示阀的工作位置&#xff0c;每个方块表示电磁阀的一种工作位置&#xff0c;即“位”。有几个方框就表示有几“位”&#xff0c;如二位三通表示有两…

JDK 14 Rampdown:内部版本27

马克 雷因霍尔德&#xff08; Mark Reinhold&#xff09;最近的帖子“ JDK 14现在处于Rampdown第一阶段 ”宣布“我们现在处于Rampdown第一阶段”&#xff0c;并且“整体功能已冻结”。 JDK 14 Early Access Build &#xff03;27&#xff08;2019/12/12&#xff09;是一个繁重…

从金蝶k3到金税盘_经典全套金蝶K3操作流程大全

—结帐—期末结帐注意点&#xff1a;不能结帐的原因&#xff1a;(1)有未过帐的凭证(2)无权限(3)其他子系统未结帐(4)与其他用户冲突八、套打1、套打格式凭证&#xff1a;*上海TR101记帐凭证上海TR102收款凭证 纸张大小&#xff1a;自定义大小上海TR103付款凭证 宽度&#xff1a…

sqlserver拼接字符串换行_1.3【Python】第三章 字符串

人工智能入门与实战第一季&#xff1a;python基础语法字符串是比较常见的数据类型&#xff0c;在第一章中我们最早接触的数据类型就是字符串&#xff1a;"hello world"&#xff0c;字符串可以用单引号’‘或双引号""来表示代码示例&#xff1a;name "…

jsf按钮响应事件_如何从JSF获取JSON响应?

jsf按钮响应事件许多JavaScript小部件都希望使用JSON格式的数据和选项。 如今&#xff0c;选择一个很酷的小部件并将其包装在一个复合组件中确实很容易。 但是第一个问题是如何发送AJAX请求并以正确的JSON格式接收响应。 JSF用户经常会提出这个问题 。 您需要的只是一个XHTML f…