概述
几乎所有语法都有语法糖;
无实质性的功能,方便开发者;
或能提高编码效率,或能提供可读性、严谨性;
常见语法糖
泛型与类型擦除
泛型思想最早出现在C++,JDK1.5引进,本质是参数化类型(Parametersized Type)。包含泛型接口、泛型类、泛型方法。Java无泛型时,经常需要开发者强制转换Object类型,运行期间必须对这些风险做处理。泛型出现后将这些风险前置到编译期间。
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 //不使用泛型 List array=new ArrayList(); array.add(“abc”); array.add(123);//编译通过 String v=(String)array.get(0);//处理ClassCastException异常 //使用泛型 List<String> array2=new ArrayList(); array2.add("abc"); array.add(123);//编译不通过 String v2=array2.get(0);
自动装箱、拆箱与遍历循环
包装类的"=="运算在不遇到算数运算的情况下不会自动拆箱
equals方法不处理数据类型转换的关系。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 /** * 自动装箱、拆箱 * <p> * a==a1 : true * c.equals(c1) : false * d.equals(a1 + b1) : false * d==a1+b1 : true */ @Test public void boxOrUnbox() { int a = 1; Integer a1 = 1; int b = 2; Integer b1 = 2; Integer c = 300; Long c1 = 300l; Long d = 3L; System.out.println("a==a1 : " + (a == a1)); System.out.println("c.equals(c1) : " + (c.equals(c1))); System.out.println("d.equals(a1 + b1) : " + (d.equals(a1 + b1))); System.out.println("d==a1+b1 : " + (d == (a1 + b1))); }
条件编译
通过推理可以预测到用于不会执行的代码会在编译时丢掉。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 /** * 条件编译 * <p> */ @Test public void conditionCompile() { if (false) { System.out.println("222222"); } System.out.println("33333"); } //编译后字节码 // access flags 0x1 public conditionCompile()V @Lorg/junit/Test;() L0 LINENUMBER 85 L0 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "33333" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L1 LINENUMBER 87 L1 RETURN L2 LOCALVARIABLE this Lcom/hardydou/lang/GrammarSugarTest; L0 L2 0 MAXSTACK = 2 MAXLOCALS = 1
此语法糖只针对if有效,其它条件语(while、for、switch)句会提醒无法编译提示:Unreachable statement
示例代码:
1 2 3 for (; false; ) {} while (false) {}
内部类
枚举
1 2 3 4 5 enum EType { A, B, C; }
编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 // class version 52.0 (52) // access flags 0x4030 // signature Ljava/lang/Enum<Lcom/hardydou/lang/EType;>; // declaration: com/hardydou/lang/EType extends java.lang.Enum<com.hardydou.lang.EType> final enum com/hardydou/lang/EType extends java/lang/Enum { // compiled from: GrammarSugarTest.java // access flags 0x4019 public final static enum Lcom/hardydou/lang/EType; A // access flags 0x4019 public final static enum Lcom/hardydou/lang/EType; B // access flags 0x4019 public final static enum Lcom/hardydou/lang/EType; C // access flags 0x101A private final static synthetic [Lcom/hardydou/lang/EType; $VALUES // access flags 0x9 public static values()[Lcom/hardydou/lang/EType; L0 LINENUMBER 131 L0 GETSTATIC com/hardydou/lang/EType.$VALUES : [Lcom/hardydou/lang/EType; INVOKEVIRTUAL [Lcom/hardydou/lang/EType;.clone ()Ljava/lang/Object; CHECKCAST [Lcom/hardydou/lang/EType; ARETURN MAXSTACK = 1 MAXLOCALS = 0 // access flags 0x9 public static valueOf(Ljava/lang/String;)Lcom/hardydou/lang/EType; L0 LINENUMBER 131 L0 LDC Lcom/hardydou/lang/EType;.class ALOAD 0 INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; CHECKCAST com/hardydou/lang/EType ARETURN L1 LOCALVARIABLE name Ljava/lang/String; L0 L1 0 MAXSTACK = 2 MAXLOCALS = 1 // access flags 0x2 // signature ()V // declaration: void <init>() private <init>(Ljava/lang/String;I)V L0 LINENUMBER 131 L0 ALOAD 0 ALOAD 1 ILOAD 2 INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V RETURN L1 LOCALVARIABLE this Lcom/hardydou/lang/EType; L0 L1 0 MAXSTACK = 3 MAXLOCALS = 3 // access flags 0x8 static <clinit>()V L0 LINENUMBER 132 L0 NEW com/hardydou/lang/EType DUP LDC "A" ICONST_0 INVOKESPECIAL com/hardydou/lang/EType.<init> (Ljava/lang/String;I)V PUTSTATIC com/hardydou/lang/EType.A : Lcom/hardydou/lang/EType; L1 LINENUMBER 133 L1 NEW com/hardydou/lang/EType DUP LDC "B" ICONST_1 INVOKESPECIAL com/hardydou/lang/EType.<init> (Ljava/lang/String;I)V PUTSTATIC com/hardydou/lang/EType.B : Lcom/hardydou/lang/EType; L2 LINENUMBER 134 L2 NEW com/hardydou/lang/EType DUP LDC "C" ICONST_2 INVOKESPECIAL com/hardydou/lang/EType.<init> (Ljava/lang/String;I)V PUTSTATIC com/hardydou/lang/EType.C : Lcom/hardydou/lang/EType; L3 LINENUMBER 131 L3 ICONST_3 ANEWARRAY com/hardydou/lang/EType DUP ICONST_0 GETSTATIC com/hardydou/lang/EType.A : Lcom/hardydou/lang/EType; AASTORE DUP ICONST_1 GETSTATIC com/hardydou/lang/EType.B : Lcom/hardydou/lang/EType; AASTORE DUP ICONST_2 GETSTATIC com/hardydou/lang/EType.C : Lcom/hardydou/lang/EType; AASTORE PUTSTATIC com/hardydou/lang/EType.$VALUES : [Lcom/hardydou/lang/EType; RETURN MAXSTACK = 4 MAXLOCALS = 0 }
断言语句
在Java中,assert关键字是从JAVA SE 1.4 引入的,为了避免和老版本的Java代码中使用了assert关键字导致错误,Java在执行的时候默认是不启动断言检查的(这个时候,所有的断言语句都将忽略!)。如果要开启断言检查,则需要用开关-enableassertions或-ea来开启。
1 2 3 4 5 6 7 8 9 10 /** * 测试断言语法糖 */ @Test public void assertTest() { int c = 2; assert c != 1 + 1; System.out.println("1111"); }
编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // access flags 0x1 public assertTest()V @Lorg/junit/Test;() L0 LINENUMBER 140 L0 ICONST_2 ISTORE 1 L1 LINENUMBER 141 L1 GETSTATIC com/hardydou/lang/GrammarSugarTest.$assertionsDisabled : Z IFNE L2 ILOAD 1 ICONST_2 IF_ICMPNE L2 NEW java/lang/AssertionError DUP INVOKESPECIAL java/lang/AssertionError.<init> ()V ATHROW L2 LINENUMBER 142 L2 FRAME APPEND [I] GETSTATIC java/lang/System.out : Ljava/io/PrintStream; LDC "1111" INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V L3 LINENUMBER 144 L3 RETURN
switch对字符串的支持
jdk1.7 switch开始支持String类型,其实switch并未修改。只是在String编译的时候通过hashcode转换为long类型而已。
示例代码:
1 2 3 4 5 6 7 8 @Test public void switchAndStr() { switch ("abc") { case "abc": System.out.println("abc"); } }
反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public void switchAndStr() { String var1 = "abc"; byte var2 = -1; switch(var1.hashCode()) { case 96354: if (var1.equals("abc")) { var2 = 0; } default: switch(var2) { case 0: System.out.println("abc"); default: } } }
try语句中定义和关闭资源
Java 7开始,jdk提供了一种更好的方式关闭资源,使用try-with-resources语句
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 /** * 资源关闭语法糖 */ @Test public void try_with_resource() { try (BufferedReader br = new BufferedReader(new FileReader(""))) { br.readLine(); } catch (Exception e) { } }
反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Test public void try_with_resource() { try { BufferedReader br = new BufferedReader(new FileReader("")); Throwable var2 = null; try { br.readLine(); } catch (Throwable var12) { var2 = var12; throw var12; } finally { if (br != null) { if (var2 != null) { try { br.close(); } catch (Throwable var11) { var2.addSuppressed(var11); } } else { br.close(); } } } } catch (Exception var14) { } }
for-each
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 /** * for-each语法糖 */ @Test public void forEach() { String[] ss = new String[]{"a", "b", "c"}; for (String s : ss) { System.out.println(s); } for (String s : Arrays.asList(ss)) { System.out.println(s); } }
反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @Test public void forEach() { String[] ss = new String[]{"a", "b", "c"}; String[] var2 = ss; int var3 = ss.length; for(int var4 = 0; var4 < var3; ++var4) { String s = var2[var4]; System.out.println(s); } Iterator var6 = Arrays.asList(ss).iterator(); while(var6.hasNext()) { String s = (String)var6.next(); System.out.println(s); } }
字面量
示例代码
1 2 3 4 5 6 7 8 9 /** * 字面量 */ @Test public void zimianliang() { int a = 10_00; int b = 1000; System.out.println(a == b); }
反编译后
1 2 3 4 5 6 @Test public void zimianliang() { int a = 1000; int b = 1000; System.out.println(a == b); }
方法变长参数
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void classTest() { build("a", "c", "b"); } public static String build(String... strs) { String r = ""; for (String s : strs) { r += s; } return r; }
反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void classTest() { build("a", "c", "b"); } public static String build(String... strs) { String r = ""; String[] var2 = strs; int var3 = strs.length; for(int var4 = 0; var4 < var3; ++var4) { String s = var2[var4]; r = r + s; } return r; }
语法糖坑
1 2 3 4 5 //无法通过编译 public static void m1(List<String> list) { } public static void m1(List<Integer> list) { }
1 2 3 4 5 6 7 8 9 10 //以下代码是错误示例 //被擦除后 两个都是MyException 无法分开。 try{ ... }catch(MyException<Integer> e){ ... }catch(MyException<String> f){ .... }
1 2 3 4 5 6 7 8 9 10 11 class O<T>{ public static var=0; } O<String> o1=new O(); o1.var=1; O<Intger> o2=new O(); o2.var=2; //此时,o1.var 跟 o2.var 是同一个。
适用于整数值区间-128 至 +127。
只适用于自动装箱。使用构造函数创建对象不适用。
1 2 3 4 5 6 Integer a2 = 1000; Integer b2 = 1000; System.out.println("a2==b2 is " + (a2 == b2));//false Integer a3 = 127; Integer b3 = 127; System.out.println("a3==b3 is " + (a3 == b3));//true