概述
什么是语法糖
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·兰丁发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。
能够带来的好处
语法糖让程序更加简洁,有更高的可读性
有哪些语法糖
- 自动拆箱、装箱
- 泛型擦除
- 不定长参数
- 迭代器
- 枚举
- switch支持枚举和字符串
- 内部类
- try-with-resources
- lambda
自动拆箱、装箱
- Java是面向对象编程(万物皆对象)
- 对象即需要new出来的,但是想想基本数据类型(int/double/boolean…),并不需要去new
- why?
- 为了方便去使用,Java对这些基本数据类型提供了装箱类型
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
| public class Demo { public static void main(String[] args) { Integer i = 1;
int j = i;
System.out.println(i + j); } }
Compiled from "Demo.java" public class Demo extends java.lang.Object{ public Demo(); Code: 0: aload_0 1: invokespecial #1; 4: return
public static void main(java.lang.String[]); Code: 0: iconst_1 1: invokestatic #2; 4: astore_1 5: aload_1 6: invokevirtual #3; 9: istore_2 10: getstatic #4; 13: aload_1 14: invokevirtual #3; 17: iload_2 18: iadd 19: inv 22: return
}
|
- 思考
- Integer的装箱类型能否用==比较?
- Integer类型的valueof方法,-128~127区间采用缓存,这部分值是可以用==比较的,区间外的是重新创建的对象,用==比较的只是引用
- ==、equals的区别?
- 为何阿里规范中心POJO以及RPC的入参、返回值的类属性定义都要用用包装数据?
- 有时候,接收到的值可能事null类型,如果用的是基本类型,则会在拆箱的过程中发生NPE
泛型擦除
- Java的泛型,其实是
伪泛型
,泛型仅仅存在于编码期间,供编译器进行类型检测,编译后,会被擦除。
- 运行时,通过类型强制转换来实现的。
- 泛型是JDK1.5之后引入
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
| import java.util.*;
public class Demo { public static void main(String[] args) { List<String> a = new ArrayList<String>(); a.add("test"); String temp = a.get(0); System.out.println(temp); } }
2. 通过jd-gui反编译后得到 import java.util.ArrayList;
public class Demo { public static void main(String[] paramArrayOfString) { ArrayList arrayList = new ArrayList();
arrayList.add("test"); String str = (String)arrayList.get(0); System.out.println(str); } }
import java.util.*;
public class Demo { public static void main(String[] args) { List<Integer> a = new ArrayList<Integer>(); List<String> b = new ArrayList<String>();
Class c1 = a.getClass(); Class c2 = b.getClass(); System.out.println(c1); System.out.println(c1 == c2); } }
|
枚举
- 枚举其实就是一个Java类,继承了
java.lang.Enum
,并且其本身是不允许被继承的
- 用
enum
修饰的
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
| public enum Demo { ENUM_A, ENUM_B }
Compiled from "Demo.java"
public final class Demo extends java.lang.Enum<Demo> { public static final Demo ENUM_A; public static final Demo ENUM_B; public static Demo[] values(); Code: 0: getstatic #1 3: invokevirtual #2 6: checkcast #3 9: areturn
public static Demo valueOf(java.lang.String); Code: 0: ldc #4 2: aload_0 3: invokestatic #5
6: checkcast #4 9: areturn
static {}; Code: 0: new #4 3: dup 4: ldc #7 6: iconst_0 7: invokespecial #8 10: putstatic #9 13: new #4 16: dup 17: ldc #10 19: iconst_1 20: invokespecial #8 23: putstatic #11 26: iconst_2 27: anewarray #4 30: dup 31: iconst_0 32: getstatic #9 35: aastore 36: dup 37: iconst_1 38: getstatic #11 41: aastore 42: putstatic #1 45: return }
|
try-with-resources
- 以前在写访问数据库、流编程,通常需要将资源关闭
- 以前使用try-catch-finally的写法,在finally中将资源关闭
- 这时候就要注意很多细节上的问题
- 资源是否打开,是否存在
- 关闭的过程中如何处理异常
- finally中不能写return
- 自从JDK7之后,支持
try-with-resources
的写法,下面简单介绍一下两种写法的区别:
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
| public static void copy(String src) { InputStream in = null; try { System.out.println(in); } catch (IOException e) { e.printStackTrace(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } }
public static void copy(String src) { try (InputStream in = new FileInputStream(src)) { System.out.println(in); } catch (IOException e) { e.printStackTrace(); } }
|
- 很明显,第二种写法较第一种,清晰、明了。
- 下面进行源码分析:
- 查看JDK7版本中的
FileInputStream
源码
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
| public class FileInputStream extends InputStream { public void close() throws IOException { synchronized (closeLock) { if (closed) { return; } closed = true; } if (channel != null) { channel.close(); }
fd.closeAll(new Closeable() { public void close() throws IOException { close0(); } }); } }
public abstract class InputStream implements Closeable { public void close() throws IOException {} }
public interface Closeable extends AutoCloseable { public void close() throws IOException; }
public interface AutoCloseable { void close() throws Exception; }
|
- 可见最终是实现了一个JDK7才提供的接口
AutoCloseable
- 我们再去查看一下
try-with-resources
写法的字节码文件
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
| Compiled from "Demo.java" public class Demo { public Demo(); Code: 0: aload_0 1: invokespecial #1 4: return
public static void copy(java.lang.String); Code: 0: new #2 3: dup 4: aload_0 5: invokespecial #3 8: astore_1 9: aconst_null 10: astore_2 11: getstatic #4 14: aload_1 15: invokevirtual #5 18: aload_1 19: ifnull 89 22: aload_2 23: ifnull 42 26: aload_1 27: invokevirtual #6 30: goto 89 33: astore_3 34: aload_2 35: aload_3 36: invokevirtual #8 39: goto 89 42: aload_1 43: invokevirtual #6 46: goto 89 49: astore_3 50: aload_3 51: astore_2 52: aload_3 53: athrow 54: astore 4 56: aload_1 57: ifnull 86 60: aload_2 61: ifnull 82 64: aload_1 65: invokevirtual #6 68: goto 86 71: astore 5 73: aload_2 74: aload 5 76: invokevirtual #8 79: goto 86 82: aload_1 83: invokevirtual #6 86: aload 4 88: athrow 89: goto 97 92: astore_1 93: aload_1 94: invokevirtual #10 97: return Exception table: from to target type 26 30 33 Class java/lang/Throwable 11 18 49 Class java/lang/Throwable 11 18 54 any 64 68 71 Class java/lang/Throwable 49 56 54 any 0 89 92 Class java/io/IOException }
|
思考
问题一
- 在第一种方案中,如果try块中抛出了异常,该异常时可以被正常抛出记录的
- 如果在finally中产生异常,然后抛出,那该异常也可以被正常记录
- 如果try中先出现异常,finally中也会被正常执行,但是如果finally中也出现了异常并抛出,try中的异常还能被捕获么?
关于异常
- jdk7之前,如果不做任何处理,try中的异常就会被忽略掉,无法捕获
- jdk7之后,引入了“可被抑制”的异常,finally中产生的异常,可以获取到try中的异常
- jdk7之前,需要实现自己的异常类
- jdk7之后,已经对Throwable类进行了修改以支持这种情况。在java7中为Throwable类增加addSuppressed方法。当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过addSuppressed方法把这些被抑制的方法记录下来。被抑制的异常会出现在抛出的异常的堆栈信息中,也可以通过getSuppressed方法来获取这些异常。这样做的好处是不会丢失任何异常,方便开发人员进行调试。
- 可以查看一下上面例子反编译后的源码:
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
| import java.io.*;
public class Demo { public Demo() { } public static void copy(String s) { FileInputStream fileinputstream; Throwable throwable; fileinputstream = new FileInputStream(s); throwable = null; try { System.out.println(fileinputstream); } catch(Throwable throwable2) { throwable = throwable2; throw throwable2; } if(fileinputstream != null) if(throwable != null) try { fileinputstream.close(); } catch(Throwable throwable1) { throwable.addSuppressed(throwable1); } else fileinputstream.close(); break MISSING_BLOCK_LABEL_97; Exception exception; exception; if(fileinputstream != null) if(throwable != null) try { fileinputstream.close(); } catch(Throwable throwable3) { throwable.addSuppressed(throwable3); } else fileinputstream.close(); throw exception; IOException ioexception; ioexception; ioexception.printStackTrace(); } }
|