jdk内置线程实例

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 

当条件为真时,对象是字符串,因此我们有“ 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代码中肯定不会偶然发生某些事情。

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

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

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

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

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

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

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

还有一种可能是放弃模式变量,而仅使用原始变量和扩展的类型信息,而当前的预览解决方案使用模式变量。 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

jdk内置线程实例

jdk内置线程实例_EA问题的JDK14实例相关推荐

  1. 自定义线程池内置线程池的使用 ThreadPoolExecutor和Executorservice 示例与注意事项

    文章目录 线程池介绍 自己设计一个线程池 1.设计ThreadPool类: 2.设计工作队列 3.实现自己设计的线程池 用java的ThreadPoolExecutor自定义线程池 自定义线程池-参数 ...

  2. Java虚拟机学习总结(3)——JDK内置工具(jps、jstack、jmap、jstat)使用详解

    一.JDK内置工具 - javap 1. 介绍 java 反编译工具,主要用于根据Java字节码文件反汇编为Java源代码文件. 2.命令 javap <options> <clas ...

  3. JDK内置命令行工具

    java命令行 序号 接口 java Java 应用的启动程序 javac JDK 内置的编译工具 javap 反编译 class 文件的工具 javadoc 根据 Java 代码和标准注释,自动生成 ...

  4. Java内置线程池ExecutorService介绍及商品秒杀案例

    第一.ExecutorService接口是java内置的线程池接口,通过学习接口中的方法,可以快速的掌握java内置线程池的基本使用 常用方法: void shutdown() 启动一次顺序关闭,执行 ...

  5. 6. JDK内置命令行工具

    JDK自带的工具和程序分为2大类型: 开发工具 诊断分析工具 开发工具 工具 简介 java Java 应用的启动程序 javac JDK 内置的编译工具 javap 反编译 class 文件的工具 ...

  6. JDK内置并发AQS同步器的独占锁获取与释放

    作者简介:笔名seaboat,擅长工程算法.人工智能算法.自然语言处理.计算机视觉.架构.分布式.高并发.大数据和搜索引擎等方面的技术,大多数编程语言都会使用,但更擅长Java.Python和C++. ...

  7. 自定义线程池-java内置线程池构造方法介绍

    Java内置线程池原理剖析 我们要想自定义线程池,必须先了解线程池的工作原理,才能自己定义线程池:这里我们通过观察java中ThreadPoolExecutor的源码来学习线程池的原理; Thread ...

  8. JDK 内置命令行工具:工欲善其事,必先利其器

    很多情况下,JVM 运行环境中并没有趁手的工具,所以掌握基本的内置工具是一项基本功. JDK 自带的工具和程序可以分为 2 大类型: 开发工具 诊断分析工具 JDK 内置的开发工具 写过 Java 程 ...

  9. Log4j日志的简单替代:JDK内置log的简单封装

    前段时间Log4j爆出严重漏洞,其实我一直都不太喜欢这个臃肿的框架. 下面代码对JDK内置的log简单地封装了一下.直接复制到项目即可用.更不需要maven. 使用方法看main函数. import ...

最新文章

  1. 什么是Sprint?
  2. 物体姿态估计数据集介绍
  3. Windows系统回顾之Windows NT
  4. 单片机 原子性操作_一款深藏功与名的国产单片机——F1C100A
  5. elasticsearch使用more_like_this实现基于内容的推荐
  6. 简单深搜(poj 3009)
  7. post 表单中常见的四种表单请求方式
  8. angualarjsdemo
  9. 2005服务器文件夹网页设设置,设置VSS2005使支持通过Internet访问
  10. Myeclipse 8.5 注册码
  11. rails 表单嵌套
  12. Codechef Black Nodes in Subgraphs(树型背包)
  13. colorUI的使用
  14. 软件设计 基础篇(一) 开发文档
  15. 为什么要在机器视觉检测中使用线阵相机?
  16. KingbaseES R6 集群手工配置VIP案例
  17. 对残差网络(ResNet/Residual Network)的基础理解
  18. MYSQL之STRAIGHT_JOIN
  19. 【产品分析】共享充电宝
  20. win10此电脑默认7个文件夹(附+ OneDrive、Catch!)隐藏方法

热门文章

  1. 一起开心2020暑假训练第一周
  2. [NOI2009] 变换序列 (匈牙利最大匹配)
  3. YBTOJ:向量问题(线段树分治、凸包)
  4. CF587F-Duff is Mad【AC自动机,根号分治】
  5. P3159-[CQOI2012]交换棋子【费用流】
  6. P3275-[SCOI2011]糖果【差分约束,负环】
  7. ssl1312ZP2502-[HAOI2006]旅行【图论,并查集】
  8. 【LCT】旅游(P1505)
  9. 【快速幂】小明解密码 (jzoj 2146)
  10. JavaFX UI控件教程(二十六)之Pagination Control