跳转至

Java应用技术3:高级语法特性

本页统计信息
  • 本页约 1995 个字, 22 行代码, 预计阅读时间 7 分钟。

  • 本页总阅读量

4. Java高级语法特性

4.1 异常处理

  • Java中的异常类型

  • 注意异常和错误的区别,系统错误是JVM抛出的,异常是由程序引起的,可以被检测出来

image-20201109161600386

  • 异常类型

  • Unchecked Exceptions 不可恢复的逻辑错误,包括RuntimeException和Error

    • 比如NullPointerException和IndexOutOfBoundsException
    • Java不需要对unchecked exceptions进行检查
  • checked exceptions 需要进行catch

  • Declaring Exceptions 方法需要声明检查的异常的种类,关键字为throws

  • Throwing Exceptions

  • 当发现了错误类型的时候可以创建一个合适的错误类型将其抛出

  • 语法是throw new TheException()
  • try-catch语句
try{
  statements;//Statementsthatmaythrowexceptions
}
catch(Exception1 exVar1){
  handler for exception1;
}
catch(Exception2 exVar2){
  handler for exception2;
}
catch(ExceptionN exVar3){
  handler for exceptionN;
}
  • tyr-catch语句块中可以加入finally子句,不管有没有找到错误都会被执行

    • 抛出异常之后如果没有finally就不会再往下执行,有finally的时候抛出异常之后还会执行finally中的语句
  • Java的异常检查使用规范

  • 不要忽略check exception:捕获就必须要处理

  • 不要捕获unchecked exception
  • 不要一次捕获所有的异常
  • 使用finally语句块释放资源,但是final块不能抛出异常
  • 抛出自定义异常异常时带上原始异常信息
  • 打印异常的时候带上异常堆栈
  • 不要同时使用异常机制和返回值
  • try不要太庞大,不然代码的可读性会降低
  • 守护线程中需要catch runtime exception

4.2 Assertion 断言

  • 包含一个在程序运行过程中一定是真的布尔表达式,用assert assertion进行定义

  • 当断言被创建的时候,Java会计算这个表达式,如果结果是false就会抛出AssertionsError这个异常

  • AssertionError有多种构造函数,用于匹配message的data type
public class AssertionDemo {
public static void main(String[] args) {
  int i; int sum = 0;
  for (i = 0; i < 10; i++) {
      sum += i;
  }
  assert i == 10;
  assert sum > 10 && sum < 5 * 10 : "sum is " + sum;
  }
}
  • 不要在public的方法中使用assertion而应该使用exception handling

4.3 文本读写

  • File 类:一个由文件名和路径组成的包装类,提供了一系列文件信息和修改操作
  • 不包含读写文件内容的方法
  • 文件读写需要Scanner和PrintWriter

  • PrintWriter 用于写入文件

  • 提供了一系列重载的print和println方法
  • 构造函数需要文件名作为变量,可以指定编码方式,比如UTF-8
  • Scanner 用于读文件
  • 初始化之后和标准输入一样使用nextXXX来读写
  • Scanner的构造方式
    • 错误方式 Scanner in = new Scanner("file.txt"); 构造了一个带字符串参数的Scanner
    • 正确方式Scanner in = new Scanner(new File("file.txt"), "UTF-8");
    • 需要用File对象进行构造
  • URL类:从web中读取信息
  • 构造方式URL url = new URL("www.xxxxxxx");
  • 完成构造之后可以用openStream打开一个输入流,用Scanner进行读取
    • Scanner input = new Scanner(url.openStream);

4.4 二进制读写

  • 文本读写是人能看懂的,二进制读写是机器可以看懂的,文本读写事实上是需要编码和解码的,但是二进制读写不需要编解码二可以直接被机器识别

  • Java通过输入输出流的形式来进行二进制文件的读写,二进制读写的一系列类的关系如下:

image-20201202110558016

  • 其中File的输入输出流需要一个文件作为读写的对象
  • Filter的输入输出流不仅可以读写二进制字符,也可以将int,double等类型的转化成二进制字符进行读写
  • 对于string类型,Java使用的是2个字节的Unicode编码,ASCII编码是Unicode的子集,String中存储的实际上是文字的Unicode序列
    • 读写的流水线:外部文件--文件输入流--数据输入流--数据读入进行操作,要写的数据--数据输出流--文件输出流--外部文件
  • 对象读写流:直接读入一个对象

  • 序列化和反序列化:可以被写入输入输出流的对象被称为是可序列化的。

  • 实现Serializable的接口,可以进行对象的序列化和反序列化

  • 序列化后的对象不需要再次调用 构造器重新生成,但是在实际中,我们会希望对象的某一部分不需要被 序列化,或者说一个对象被还原之后,其内部的某些子对象需要重新创 建,从而不必将该子对象序列化
  • 反序列化之后得到的对象和原来的不是同一个,因此是深拷贝

  • 高级的文本I/O

image-20201202115828956

4.5 Generics 泛型

  • 是一种对变量类型进行参数化的功能,类似于C++中的模板
  • 优点是能在编译期就发现一些错误而不是运行时
  • 一个泛型类或者方法可以声明类名和函数名作为变量

4.5.1 泛型方法

  • 泛型方法的类型参数声明要卸载返回值类型前面,用尖括号括起来,比如
  • public static <E> void printArray(E[] input);
  • 类型参数可以有多个参数,有逗号隔开,类型参数可以被用来声明返回值类型
  • 有界限的类型参数:可以让类型参数有一定的范围
    • 用extends关键字+类型的上界来控制类型的范围
    • 比如<T extends Comparable<T>> 表示T必须是可以比较大小的类型
  • JDK7之后后面一个类型可以省略,由Java编译器自己推断

  • 判断函数中的范型参数能否被接受:画范型的继承关系,比如下面这样:

  • 这张图中,上层的可以容纳下层的对象

image-20201230102245681

4.5.2 泛型类

  • 类型参数的声明添加在类名的后面

  • 参数化类型没有实际类型参数的继承关系

  • 比如List<Integer> list = new List<Object>会编译错误,把两个参数类型反过来也是编译错误
  • 泛型的继承关系需要通过通配符

    • 使用?代替具体类型参数,比如List<?>可以代表所有具体类型List的父类
    • 比如List<? extends Number>表示参数的泛型上限为Number类型
    • List<? super Number>表示参数的泛型下限为Number类型
  • 不允许用泛型类型来创建泛型数组

  • 范型的实现方式:

  • 范型使用一种叫做类型擦除的方法来实现,编译器编译的时候使用范型类型来编译代码,随后将其删除,因此范型信息在运行时是不可知的,这个方法使得范型可以向后兼容旧代码。

image-20201230103159673

  • 泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例共享的。所以在静态方法、数据域或初始化语句中,为了类而引用泛型参数是非法的

4.6 Collection 框架

  • Java的一系列范型容器,主要支持的类型是集合、列表和映射

  • 其中Set和List是Collection接口的子接口,set是内容无序的,而list是有序的

    image-20201230105441871

  • 而Map是一种key-value的映射

    image-20201230105539284

  • hashcode的使用方式:在接口中定义的hashcode是里面所有元素的映射,可以通过维护hashcode来方便对象之间进行的比较,比如equals等方法,只需要比较hashcode就可以

  • LinkedHashSet相比普通的HashSet,也使用hashcode来决定元素的存储位置,并用链表维护元素的顺序,所以性能比HashSet要差

image-20201230111417175

image-20201230111620049

image-20201230112153297

  • 迭代器陷阱:迭代过程中不能发生结构上的变化,比如插入删除,否则会出问题

  • 因为迭代器是根据位置来进行的,会维护索引相关的数据,这一部分数据不能发生变化,否则会出问题

  • Collection还有Vector、Stack、Queue、PriorityQueue等list结构,map可以
  • 枚举集合和枚举map

  • EnumSet提供了非常方便的方法来创建枚举集合,枚举集合中的所有元素必须都来自于单个枚举类型

颜色主题调整

评论区~

有用的话请给我个star或者follow我的账号!! 非常感谢!!
快来跟我聊天~