语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。 来自百度百科
关于语法糖之前听过,但是没怎么深入的了解过。今天举几个简单,常用的例子。比如switch,增强for循环,if,数值字面量。下面我们一起来看一下。
第一块糖:switch
switch对于char, byte, short, int类型是本身就支持的,但其实它们都是转换成了整型,最后支持的其实是整型。但由于Java语法糖的出现,switch也支持String和enum类型了
原代码
public class SugarTest {
public static void main(String[] args) {
String str = "java";
switch (str) {
case "java":
System.out.println("1");
break;
case "javac":
System.out.println("2");
break;
default:
System.out.println("default");
}
}
}
编译后代码
public class SugarTest {
public SugarTest() {
}
public static void main(String[] args) {
String str = "java";
byte var3 = -1;
switch(str.hashCode()) {
case 3254818:
if (str.equals("java")) {
var3 = 0;
}
break;
case 100899457:
if (str.equals("javac")) {
var3 = 1;
}
}
switch(var3) {
case 0:
System.out.println("1");
break;
case 1:
System.out.println("2");
break;
default:
System.out.println("default");
}
}
}
可以看出,switch对于字符串类是比较字符串的hashcode方法以及通过equals方法确定是哪个字符串的,由于hashcode有一定概率会出现hash碰撞,用hashcode比较可能不太安全,所以仍需要进一步通过equals比较
第二块糖:自动拆装箱
自动拆装箱实际上是通过包装类的valueOf方法和xxxValue方法实现的,具体见我的一篇博客专门介绍自动拆装箱
第三块糖:for-each语法
增强for循环可谓是广泛使用,省去了去定义一个自增变量
public class SugarTest {
public static void main(String[] args) {
String[] strs = new String[]{"java", "python", "c++"};
for (String str : strs) {
System.out.println(str);
}
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add(i);
}
for (Integer num : list) {
System.out.println(num);
}
}
}
编译后代码
public class SugarTest {
public SugarTest() {
}
public static void main(String[] args) {
String[] strs = new String[]{"java", "python", "c++"};
String[] var2 = strs;
int i = strs.length;
for(int var4 = 0; var4 < i; ++var4) {
String str = var2[var4];
System.out.println(str);
}
List list = new ArrayList();
for(i = 0; i < 3; ++i) {
list.add(i);
}
Iterator var7 = list.iterator();
while(var7.hasNext()) {
Integer num = (Integer)var7.next();
System.out.println(num);
}
}
}
可以看出,一般的数组使用for-each背后的实现仅仅是把它变为普通fot循环而已,对于集合类使用for-each循环背后的实现是使用了Iterator遍历的
由于使用了迭代器Iterator,所以在数组遍历时不能修改数组(比如调用remove方法),否则根据fail-fast机制会抛出java.util.ConcurrentModificationException异常
第四块糖:方法变长参数
Java是允许将一种类型的任意数量的值作为参数使用的
public class SugarTest {
public static void main(String[] args) {
test("java", "python", "c++");
}
public static void test(String... strs) {
for (String str : strs) {
System.out.println(str);
}
}
}
编译后的代码
public class SugarTest {
public SugarTest() {
}
public static void main(String[] args) {
test("java", "python", "c++");
}
public static void test(String... strs) {
String[] var1 = strs;
int var2 = strs.length;
for(int var3 = 0; var3 < var2; ++var3) {
String str = var1[var3];
System.out.println(str);
}
}
}
事实上就是将参数转变为了对应的数组
第五块糖:if条件编译
条件编译就是在编译期间编译器会选择有效的代码编译,不满足条件的代码称为无用代码,会被直接丢弃
public class SugarTest {
private static final boolean DEBUG = true;
public static void main(String[] args) {
if (DEBUG) {
System.out.println("DEBUG模式");
} else {
System.out.println("非DEBUG模式");
}
}
}
编译后的代码
public class SugarTest {
private static final boolean DEBUG = true;
public SugarTest() {
}
public static void main(String[] args) {
System.out.println("DEBUG模式");
}
}
上面的代码中编译器在编译时已经能确定只用执行DEBUG为true的代码,那么编译器只需要保存满足条件的一行代码即可,不需要全部保存
谈一谈条件编译的作用
有人会问了,既然DEBUG已知为true了,还去写个if多此一举干嘛,这其实是为了后期便于维护,就像上述代码一样,DEBUG模式可能是一段代码,非DEBUG模式可能是另外一段代码,开发者只需要改变常量DEBUG的值即可做到两种模式下的自由切换,岂不乐哉?这样配合编译器的条件编译机制又能使编译后的代码更为简洁,简直perfect!(通常这个常量可通过配置文件配置更为简便)
差不多我们平时写代码常用的就这些,具体可以参考这篇,我这篇博客也是转载这个大佬的。他还写了其他的语法糖,感兴趣的小伙伴可以去看一下。
其实就我而言可能面试官会问我是否了解java的语法糖,然后简单的举几个例子就可以,比如switch这个例子就很好,很好理解我们在写程序的时候也经常使用。
还有if,和数值字面量都可以说给面试官。但是我们面试的时候不可能把12条都说出来,把我们记住,理解的说出来就好了。但是我们平时自己学习还是多了解一下,对我们还是有好处的,不理解也没什么大问题,先记住有这么回事就可以了。