漫谈 IDEA 设置 JDK 版本
背景
IDEA里是相当多的地方可以设置JDK版本,很多资深的开发都未必知道其中区别,以及设置后产生的影响。当然本人也没有完全搞清楚,所以也需要众人拾柴。
如果出现版本的问题,比如编译错误,运行时提示版本错误,一般来说,版本都保持一致,就不会有问题。
仔细阅读本文,你会有不少收获的
IDEA里可设置JDK/JRE版本的地方
大略看看即可,这个子标题只列出可以设置jdk版本的地方,关于它的作用,在后续的标题下进行分析。
1、项目结构-Project
File->Project Structure...->Project
,图1
2、项目结构-Modules
File->Project Structure...->Modules -> Sources | Dependencies
,图2
3、新项目结构-Project
File -> New Projects Settings -> Structure for New Projects...
, 图3
4、Java Compiler里
File -> Settings -> Build,Execution,Deployment -> Compiler -> Java Compiler
,图4
(有时候Module列表是是空的,一般是非Maven项目是空的,当然加是可以加上,只是没必要加)
5、Run Configuration里
Edit Configurations...
(图5)
这个一般是main方法运行过后就会出现,也可以自行添加。有个JRE的版本的设置
说明
对上述可以设置JDK/JRE版本的各个地方做一个解读。
下面说的Project指的是项目工程,“项目”、“工程”、“项目工程”、“Project” 都是指通过File->new->Project… 建的东西;
“模块”、“Module”,都是指Project下的一个模块,在某个Project下也是可以File->new->Module的。
当然一般一个Project对应一个Module,也可以在一个Project下建多个Module
1、项目结构-Project (图1)
-
仅本Project有效,其他不受影响
-
修改的是本Project默认值,现有的Module不受影响(说明1),新建的Module用新值
说明1:现有 Module 如果设置 Language level 为 Project default,或者 Module SDK 设为Project SDK,则会跟随 Project 配置的变动而变动
-
Project SDK 和 Project language level 有什么区别?见后面
2、项目结构-Modules (图2)
-
修改仅影响本Module,其他不受影响
-
Language level (Sources)
配置 IDEA用什么版本校验语法
如果是非Maven项目,也是编译java文件的版本; maven项目不决定于这里,而决定于Java Compiler配置里的
-
Module SDK (Dependencies)
是说项目引入的JDK依赖库。Module SDK 的改变,会导致 External Libraries 的改变。
-
如果设置为 Project default 和 Project SDK,Module的值会跟随Project的改变而改变
如果不想Module跟随,改成其他固定值
-
Language level,会受到
maven.compiler.source
的影响 (maven项目才有) 详见后续 "关于maven的配置"
3、新项目结构-Project (图3)
新建项目的使用使用的(继承的)设置。只有Project设置,没有Module设置。
- 显而易见,这是IDEA新建一个项目的时候采用的配置
- 跟Project Structure的区别是:这里的配置是全局的,针对所有的新建的项目
- 改变这里不影响已有的项目
4、Java Compiler里 (图4)
-
作用是指定class文件要用什么版本编译成的class
-
非Maven的Project没有module,非Maven的项目,用什么版本编译java文件,决定于Language level的配置。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bwUqloxv-1623407192147)(C:\Users\xuanxiao\AppData\Roaming\Typora\typora-user-images\image-20210611160542273.png)]
- 对于Maven项目,会受到
maven.compiler.target
的影响。详见后续 "关于maven的配置"
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
5、Run Configuration里 (图5)
是说运行程序用的是什么版本的 JRE
- 如果是用1.8编译的,JRE选1.7肯定是无法运行的,可以选择>=1.8的,比如用1.9是可以的
- 默认的值是 Default,即跟随Module SDK (即 Modules->Dependencies->Module SDK)
补充
1、究竟Language Level是干嘛的
- 在非Maven项目里,这是管编译java文件用什么版本的
- 在Maven项目里,是配置给IDEA看的,让IDEA用指定版本的语法检查你的源码。
例如 JDK5 引入了泛型,可以这么写:
List<String> list = new ArrayList<String>();
但是不能这么写:
List<String> list = new ArrayList<>();
这个写法要到JDK7之后才可以,所以如果Language level 小于7(比如5或6),IDEA会提示你语法错误,但是改成>=7的版本就不提示错误了。所以这个配置就是告诉 IDEA用什么版本的语法检查源码,以便提示编译错误。
2、关于maven的配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
-
maven.compiler.source
的值决定了 Language level 的配置如果将 Language level 修改成不一致,在 reimport(刷新) Maven配置后会恢复成
maven.compiler.source
的值 -
maven.compiler.target
的值决定了 Java Compiler里的target bytecode version跟上面一样,如果两者指定的版本不一致,在刷新Maven后会恢复
-
如果Maven项目没有上述配置,则默认都是1.5
会发生 “即使你改了 Language level 和 Java Compiler 里的 target bytecode version”,刷新后恢复成1.5
最佳实践:maven项目最好有这个配置
reimport 是指这里
3、关于 System.getProperty("java.version");
是什么版本?
是JRE的版本,不是class的编译版本。
比如你的源码是jdk8编译的,如果在Run Configuration里修改为jdk9的版本,获得的值是9的版本,说明这里获得的值是JRE。
4、如何知道class是用什么版本编译的
有多种方法
-
双击打开class文件,会显示(最方便)
-
用jclasslib
-
用javap命令
javap命令,无论用
javap -v -p Xxx.class
还是javap -v
能看到major version
就行
5、关于Java Compiler里有时候会空的
非Maven项目默认是没有Module的 (maven项目默认会有)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X1B3I498-1623407192155)(C:\Users\xuanxiao\AppData\Roaming\Typora\typora-user-images\image-20210611160542273.png)]
当然是可以点击+号添加的。不添加,则编译的版本跟Language level保持一致。很明显,你手动添加后也可以看到,也提示你 Same as language level
这里确实是可以改成和language level的版本不同(不过谁吃饱撑着改成版本不一),但是会导致Information:java:javacTask:源发型版本xxxxx
的错误。
6、我如何添加sdk版本?
先安装,自己选择需要的版本即可,不需要都装。另外很多的jdk安装的时候会提示安装jre(少数不会,好像jdk5就不会),不需要安装,我留了一个jre8。
在 IDEA 里进行添加,
在File->New Projects Settings->Structure for New Projects…->Platform Settings->SDKs里进行添加,是全局的
或者在File->Project Structure…->Platform Settings->SDKs里进行添加,也是全局的。
常见的关于JDK版本的报错
1、Diamond types are not supported at language level ‘5’
修改language level即可能可以临时解决。
diamond指钻石,即钻石符号(
<>
),长得像钻石吧!所以看到diamond这个单词,就要想起这个符号,sql里也用这个表示 “不等于”。jdk5里虽然有泛型的写法,但是这种写法
List<String> list = new ArrayList<>();
只有jdk7之后才能用钻石符号,否则就怪怪不省略,使用List<String> list = new ArrayList<String>();
为什么说可能是临时的解决方案?
因为对于非maven的项目,你在Project Structure里Modules里改了Language level就是改了,但是对于maven项目,你改了有可能会打回原型,必须配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
PS: 下面是细节,以前我以为 Diamonds 是指泛型,犯过错,曾经也稀里糊涂
2、java.lang.UnsupportedClassVersionError: com/wyf/test/non/T : Unsupported major.minor version 52.0
举个例子,如果你的class是jdk8编译的,如果你切换成7运行。
这里的 52.0 是不支持的版本,指你的class文件是用52版本编译的,不支持。
为什么会不支持?
你用52版本编译的,肯定不能用低于52的JRE运行。这里你肯定用了<52版本的JRE在运行它。
52指 jdk8,51指 jdk7,53是 jdk9,如此类推。
解决方法:提高Module SDK的版本,由于Run Configuration里JRE的设置一般是跟随Module SDK的
3、Information:java: javacTask: 源发行版 8 需要目标发行版 1.8
这个乍看错误提示似乎不太好定位问题所在,不过肯定是配置的问题。那怎么解决呢?你把本文提到的那些配置的地方,检查一下,改成一致版本。