java语法糖
导读
这两天博主在复习阶段,整理出来了一些常用的语法糖,那么下面就跟着我来看看java中有哪些常用的语法糖
java中的语法糖简单理解就是java中的一些特殊的语法,他可以帮助我们来更好的理解代码,提高代码的可阅读性,以及提高编程的效率,具体详解可以到百度百科看看语法糖更加详细的介绍。
注意:因为他们的出现jdk版本不同,在使用的时候一定要对照好自己的jdk版本,下面我也会特别标注jdk的版本号。
具体分类
这些语法糖包含条件编译、断言、Switch语句与枚举及字符串结合、可变参数、自动装箱/拆箱、枚举、内部类、泛型擦除、增强for循环、lambda表达式、try-with-resources语句、等等
这里我就简单介绍几种
for - each(JDK5.0)
首先就是我们最常用的for - each,他的语法与for循环十分相近。而他就是根据C语言中的for循环扩展而来的一种新的遍历数组的循环方式。
本质上for - each的底层是用迭代器实现的,那么我们上一段代码看看它的具体使用
@Test
public void each(){
String[] each = {"hello", "java", "word"};
List<String> list = Arrays.asList(each);
for (Object s : list) {
System.out.println(s);
}
那么具体我们在什么时候使用它?先让我们看看for - each的优缺点
优点
- 语法简介
- 在遍历过程中不需要关心下标越界异常
- 在使用循环遍历时性能与使用for循环的性能相近
缺点
- each不可以删除元素/替代元素
- 无法获取当前索引
- 只能正向遍历
- 不能同时遍历两个集合
而在实际开发中我列举了三种类型的队形可以适用for - each的场景
- 数组
- Collection类
- 任何实现了Iterable接口的自定义类
自动装箱、拆箱(JDK5.0)
自动装箱简单理解就是自动将基本数据类型转化为包装类型,而拆箱就是这个过程反过来引用类型转化为基本的数据类型
首先我们需要知道最基本的八大数据类型以及他们的的引用类型对应的下图。
那么具体什么是自动装箱和拆箱呢?
这里我们举一个简单的例子:
int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。
下面我就简单介绍一下自动装箱与拆箱的应用场景
- 在使用java集合时候不能直接将基本数据类型传入到集合中,因为集合只接受对象,所以这个时候我们就会用到自动装箱和拆箱。这也就是我们可以直接add一个基本数据类型而不报错的原因
- 当我们使用基本数据类型和引用数据类型比较的时候“ == ”
- 调用一些方法的时候
最后我们简单的说一下它的一些缺点
在自动装箱过程中会创建对象,频繁的装箱操作会消耗许多内存,增加GC的压力(这里我会详细出一篇关于GC的博客),从而影响性能。
而如果我们没有初始化一个值的时候,会产生混乱。
枚举类(JDK 8)
首先我们来看一段代码
public class shootGame extends JPanel {
public static final int WIDTH = 400; //面板的宽度
public static final int HEIGHT = 654; //面板的长度
// 定义游戏的状态
public static final int START = 0; // 开始
public static final int RUNNING = 1; // 运行
public static final int PAUSE = 2; // 暂停
public static final int GAME_OVER = 3; // 结束
}
上面是我做的游戏中的一些状态,但是当在调用的时候我想知道这个转态是什么,还想把这个转态打印出来,就需要我们来使用一些方法封装,并且使用私有来防止外界创建私有的类。这样做显然十分的麻烦。
这个时候我们就需要一个类来简化这个操作
public enum Type {
START(1), RUN(2), PAUSE(3), GAME_OVER(4);
private int Value;
private Type(int Value) {
this.Value = Value;
}
}
但是使用枚举类需要注意下面几点:
- 一定要把枚举类变量的定义放在第一行,并且以分号结尾。
- 构造函数需要私有化,他默认就是私有化,就算你不写他也会默认private。
try-with-resource(JDK 7.0)
try-with-resource是JDK7新加的异常处理机制,他的作用是可以关闭在try - catch语句块中使用的资源。
java1.7的版本中引入的新特性:多个异常并列在一块
实例代码如下:
try {
background = ImageIO.read(shootGame.class.getResource("Img/background(1).png"));
} catch (IOException e | RuntimeException r){
e.printStackTrace();
}
需要注意的是并列的多个异常不能有(直接/间接)继承关系,否则就会报错
下面我们放一张异常的关系图
数值字面量下划线(JDK 7.0)
如下当我们定义一个量的时候,这个值比位数比较多的时候(比如:整形类型用二进制赋值)
这个时候我们就可以在它们中间添加一些下划线,增加数值的可读性
// π的值
double pi = 3.14_15_92_65_36;
// 一个32位的二进制数,最高位为符号位。
int binVal = 0B1000_0000_0000_0000_0000_0000_0000_0011;
System.out.println(pi);
System.out.println(binVal);
注意:这个下划线只能放在数字的中间
上图为运行结果和正常的输出是没有任何区别的
但是这样做却能更加直观的看出数的位数,总的来说这颗语法糖还是挺不错的
var(JDK 10)
这颗语法糖是java的一个比较新的特性,它的实现是靠jvm自动为他设置类型。
那么我们为什么需要使用var ?
首相我们要知道java是一种强类型语言,就是一旦定义了某一个变量,如果不经过强制类型转化,那么它永远就是该数据类型。而var是弱类型语言特有的一种定义方式(比如:js中的定义一个变量)那么这颗语法糖的优点就在于,它是通过jvm的自动判断为你赋值,而这个变量一旦定义就明确了类型,就不可以再次更改。
首先我们来看它的实例代码
var s = "lalla";
var i = 123;
i = "sss";//erro 不能再为它赋其它类型的值
var user = new UserDetailsOInterest();
那么我这里就列举它的一些好处
- 这样做就可以避免类型的冗余(比如一个很长的引用类型名)
- 对齐变量名
- 使得更加容易阅读
但是它也有一定的限制和缺点
最好使用在局部变量
一个变量确定了之后,就不能推断出来它的类型了
一个类型被推断出来了,那么他就不能再为这个值赋其他类型了
不能使用复合语法
不能使用null
尽量避免大量使用,会使得代码的可读性变差
不能用在返回类型
Switch Expressions(JDK 12)
话不多说我们先上一段实例代码
/**
* 判断输入的月份有多少天
*/
switch (s) {
case "JAN":
case "Mar":
case "May":
case "Jul":
case "Aug":
case "Oct":
case "Dec":
System.out.println(31);
break;
case "Feb":
System.out.println(29);
break;
case "Apr":
case "Jun":
case "Sept":
case "Mov":
System.out.println(30);
break;
default:
System.out.println("请输入正确的月份");
}
可以看到这样写非常的冗余,而且还容易出错
那么让我们在看看switch这颗语法糖
/**
* 判断输入的月份有多少天
*/
int i = switch (s) {
case "JAN", "Mar", "May", "Jul", "Aug", "Oct", "Dec" -> 31;
case "Feb" -> 28;
case "Apr", "Jun", "Sept", "Mov" -> 30;
default -> {
System.out.println("请输入正确的月份");
}
};
System.out.println(i);
同样的一个案例在表达的作用相同的情况下,显然下面的这一段逻辑更加清晰,也更复合开发者的逻辑判断,即降低了代码量也提高了效率。
那么下面简单总结一下它需要的一些注意事项吧
- 对应的多个case合并到一块,增加代码的阅读性
- 条件于动作之间用 ->来连接,如果遇到匹配的分支则直接跳出分支,不需要写break。
- 每一个 -> 后面只允许接一个表达式、代码块、或者throw语句。
范式(JDK5.0)
首先让我们来看一段实例代码
@Test
public void normalForm() {
List s = new ArrayList();
s.add(1);
s.add("2");
s.add('a');
s.add(true);
for (Object o : s) {
System.out.println("定义集合输出o:"+o);
}
}
在集合中实例化一个ArrList时候add方法添加元素的时候编译可以通过,但是在运行的时候就会报错
所以这个时候范式的作用就凸显出来了
- 它的主要作用就是在编译的时候检查类型安全,并且所有的强制类型转化都是自动和隐饰的
- 它的原理就是“类型的参数化”,把类型看作一个参数。也就是说把所要操作的数据类型看作参数,就像方法的形式参数是运行时传递的占位符一样。
好的那么我们接下来添加范式,但是添加也有许多要注意的点啊!
-
规范
- 类:Arraylist ,HashSet,HashMap
- 方法:Coolections.binarySearch,Arrays.sort
- 接口:List,Iterator -
范式的应用场景
- 当添加的类型约束只作用于一个方法的多个参数之间就使用范型方法
- 添加类型约束的方法为静态方法,只能定义为范型方法,因为静态方法不能使用其所在的类型参数
/*
* 就比如这样写就不行了,如果要这样输出,在这个静态方法static关键字前面,增加<T>,也声明为泛型方法
*/
class A<T> {
private static T a;
public static void a() {
System.out.println(a);
}
}
好了语法糖的几个基本的介绍就到这里吧~~
——————————————————————————————————