1 异常
抛出异常格式:
选中要生成try catch的代码——右键——surround With——try /catch Block
public class Test{
try{
}
catch(Exception e//异常类型){
//捕获到异常后怎么处理它
}
catch(Exception e//异常类型){
}
catch(Exception e//异常类型){
}
finally{
//无论程序是否异常,都会执行的代码段
}
}
- 注意:
1.一个try可以对应一个或者多个catch
2.如果try中有一个语句发生异常,则这句语句后的其他语句将不执行
3.异常也有父类子类,如果要写多个catch,catch中异常的顺序,需要先写子类(小类型)的异常,再写父类
4.catch(异常 | 异常 | 异常),这里要注意的是,异常是需要是**同级(兄弟关系)**的异常,否则报错
5.Java允许
try{
}
catch(Exception e){
}
try{
}
finally{
}
1.1 常见异常
- 数组下标越界异常ArrayIndexOutOfBoundsException:4
public class TestTryCatch{
//throws Exception 向上抛出异常(谁调用就抛给谁)最后是JVM
public static void main(String[] args) throws Exception{
try{ //抓
int[] array = {1,2,3};
System.out.println(array[4]);
}
catch(Exception e){ //捕获
e.printStackTrace();//打印栈轨迹
//System.out.println("系统异常,请联系管理员");
//System.out.println("数组下标越界");
//坑爹的:什么都不做
}
System.out.println("gpgo");
//finally无论有没有错误,都会执行
//finally{
// System.out.println("finally");
//}
}
}
- 空指针异常NullPointerException
//创建一个字符串空引用
String str = null;
//此时又想调用“str”的属性或者方法
System.out.println(str.length());
- 输入类型转换异常InputMismatchException
Scanner a = new Scanner(System.in);
int b = a.nextInt();
System.out.println(b);
- 数学异常ArithmeticException
Scanner a = new Scanner(System.in);
System.out.println(a.nextInt()/0);
- 类型转换异常ClassCastException
public class Example {
public void ti(String str) {
System.out.println(str.length());
}
public static void main(String[] args) {
Object str = new String();
Example e = (Example)str;
}
}
1.2 错误Throwable分类
分为:
-
异常Exception:程序运行时发生的不正常事件,异常能够被程序处理,保证程序运行下去;例如除数为0
-
错误Erro:程序运行期出现,通过异常处理无法解决;例如内层溢出,需要修改代码才能解决相关错误
此外,Throwable是Exception和Error标准父类子类 -
异常Exception中——栈溢出异常StackOverflowError
main(null);
- 异常Exception中——堆溢出异常OutOfMemoryError heap堆
int [] array = new int[1024*1024*1024];
1.2.1 Exception分类
Exception分为运行时异常和非运行时异常。
- 其中RuntimeException的子类是运行时异常(也叫非检测异常),其他都是非运行时异常(检测异常)
1.3 throw和throws
1.3.1 throw
- throw 手动引发一个异常——异常对象,也就是创建了一个异常对象,用throw交给异常处理机制去处理
- 与编码过程遇到一些特殊业务逻辑有关
- 更直接、更明显的异常处理——制造异常
- 抛出异常的方式:
throw new RuntimeException();
catch(Exception e){
throw e;
}
public class ExampleException{
public static void main(String[] args) {
t("10");
}
public static void t(String s) {
if (s.length()<10) {
throw new RuntimeException("长度不能小于10");
}
}
}
1.3.2 throws
- 一直向上抛出,谁调用这个就抛给谁,最后给JVM
- 让调用者进行异常的处理
*
public class ExampleException{
//throws Exception 向上抛出,谁调用就谁异常处理
public void setName(String name) throws Exception{
if (name.length()<=5) {
//这是异常,手动引发一个异常
//Exception 包含了runtime和非runtime
throw new Exception();
}
}
//throws Exception -> JVM
public static void main(String[] args) throws Exception {
ExampleException EE = new ExampleException();
EE.setName("isi");
}
}
1.3.3 自定义异常(异常不够用则新定义)
步骤:
1.继承Exception或者Exception下的某个子类
2.构造方法中加入合适的参数、必要的构造方法的重载
3.合适场景中,使用throw new 自定义异常类()
public class ExampleException extends RuntimeException {
public ExampleException() {
super();
}
public ExampleException(String str) {
super(str);
}
public static void main(String[] args) {
throw new ExampleException("长度不能小于10");
}
}
1.4 return
- 类似break用法——结束后续代码执行,终止方法
- 和break不同的是,分支上可以有多个return,但是以最后一个为准
情况1
public class TestReturn {
public void t1(int n) {
System.out.println("t1-----------1");
if (n > 1) {
//n = 10 条件成立
//结束了方法后续的执行
return;
}System.out.println("t2-----------2");
}
public static void main(String[] args) {
new TestReturn().t1(10);
}
}
情况2
public class TestReturn {
public int t1(int n) {
try {
System.out.println("执行了try");
return 0;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("执行了catch");
return 1;
}finally {
System.out.println("执行了finally");
//finally block does not complete normally
//因为可能有两次return,但是不影响程序执行
return 2;
}
}
public static void main(String[] args) {
int n = new TestReturn().t1(10);
System.out.println(n);
}
}
情况3
int a = 10;
try {
System.out.println(1/0);
System.out.println("执行了try");
return ++a;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("执行了catch");
return ++a;
}finally {
System.out.println("执行了finally");
//finally block does not complete normally
//因为可能有两次return,但是不影响程序执行
return ++a;
}
情况4
int a = 10;
try {
System.out.println(1/1);
System.out.println("执行了try");
return ++a;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("执行了catch");
return ++a;
}finally {
System.out.println("执行了finally");
//finally block does not complete normally
//因为可能有两次return,但是不影响程序执行
return ++a;
}
情况5
int a = 10;
try {
System.out.println("执行了try");
return 1;
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("执行了catch");
return 2;
}finally {
System.out.println("执行了finally");
//finally block does not complete normally
//因为可能有两次return,但是不影响程序执行
return 3;
}
1.5 断言
关键字:assert
-
默认情况下是没有开启断言的功能的
-
开启断言 -ea
-
调试程序中使用,只是程序调试的方式
assert<布尔表达式>
assert<布尔表达式>:<错误信息>
- 当布尔表达式的值是true时,忽略assert
- 当布尔表达式的值是false时,发生AssertionError错误,程序中断,如果用第二种形式同时显示错误信息
public class TestAssert {
public void t1() {
int n1 = 2;
int n2 = 2;
System.out.println("t1 --1:" + n1);
// assert n1 != 1;
//t1 --1:2
//t1 --2:2
assert n1 == 1:"我是你们最爱的断言提示";
System.out.println("t1 --2:" + n2);
}
public static void main(String[] args) {
TestAssert ta = new TestAssert();
ta.t1();
}
}
2 集合
使用方法:看无参有参构造,再实例化调用
Collection
list接口 ——awt包下
List组件向用户显示文本项的滚动列表。 可以设置列表,以便用户可以选择一个项目或多个项目。
——java.util下
有序集合(也称为序列 )。 该界面的用户可以精确控制列表中每个元素的插入位置。 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
- 泛型:
没有写泛型——for(Object book : list)
写了泛型——for(Book book : list) 不需要再进行类型转换,取出来就是Book类型
//接口的引用 指向实现类对象
接口<任意类型1> 引用名 = new 接口<任意类型2>();
//ArrayList<String> alist = new ArrayList<String>();
//任意类型1需要和任意类型2保持一致
2.1 ArrayList
ArrayList注意点:
- 长度可变,类型可以固定,也可以Object;提供了大量的算法实现。如ArrayList
- ArrayList是一个用数组实现的列表
- ArrayList底层是Object类型的数组
- 元素可以重复,可以为null,如果是两个重复的数据,remove会删除前面那个
- 可以精确定位,也就是通过get(index)索引来定位
ArrayList优点:
- ArrayList底层以数组实现(随机访问模式)(实现了RandomAccess接口,所以get很快)
- ArrayList顺序添加一个元素只是往数组添加了一个元素而已,非常方便
- 可以自动扩容,默认每次扩容变成原来的1.5倍,默认情况下,容量为10
ArrayList缺点:
- 插入和删除元素的效率不高
- 根据元素下标查找元素需要遍历整个元素数组,效率不高
- 线程不安全
练习:
控制台输入五个人的姓名,存在集合里面,再输出出来
public class TestArrayList {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("请输入五个人的名字");
Scanner s = new Scanner(System.in);
//实例化ArrayList对象
ArrayList<String> alist = new ArrayList<String>();
for (int i = 0; i < 5; i++) {
String name = s.next();
alist.add(name);
}s.close();
System.out.println("**********结果foreach循环:************");
for (String string : alist) {
System.out.print(string + " ");
}System.out.println();
System.out.println("**********结果for循环:***************");
for (int i = 0; i < alist.size(); i++) {
System.out.print(alist.get(i) + " ");
}
//在下面结果栏没有显示出来
System.out.println("**********结果用Jdk foreach直接输出集合:***************");
//JDK1.8后才有!
list.forEach(System.out::println);
}
}
- List接口为Collection子接口,List所代表的是有序可重复、有索引的Collection,add() get() remove()
- list.size();获取大小 list.get()获取 list.add()添加数值 list.remove()删除数据
扩展:如何观察得到扩容的过程?
扩容得到原来的1.5倍
练习:
定义一个Student类,id和name,实例化3个学生对象,将3个学生对象添加到集合中,再使用for或者foreach遍历出来
import java.util.ArrayList;
public class Student {
//属性私有化
private String name;
private int id;
//无参构造
public Student() {
super();
}
//有参构造
public Student(String name, int id) {
super();
this.name = name;
this.id = id;
}
//提供公共getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//提供toString方法
@Override
public String toString() {
// TODO Auto-generated method stub
return "姓名:" + name + "\t" +"学号:" + id;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//实例化三个对象并给值
Student s1 = new Student("小明",12);
Student s2 = new Student("小春",15);
Student s3 = new Student("小刀",13);
//实例化ArrayList对象
ArrayList<Student> list = new ArrayList<Student>();
//添加list到ArrayList中
list.add(s1);
list.add(s2);
list.add(s3);
//for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//foreach
for (Object object : list) {
System.out.println(object);
}
//直接输出集合
System.out.println(list);
//JDK1.8
list.forEach(System.out::println);
}
}
2.1 linkedlist
- 特别的是,相较于ArrayList,增加了对头部尾部插入的操作,如getFirst() getLast() addFirst() addLast(),remove(),removeFirst(),removeLast(),但底层实现时调用的方法一致,没什么大区别。
- 支持泛型
- linkedlist底层的实现是双向链表,在添加和删除元素时具有比ArrayList更好的性能,但非线程安全
2.2 vector
- protect object[] obj 底层也是数组
vector特点:
- 相较于ArrayList,vector的方法带有synchronize关键字修饰,表示支持线程同步
- 常见方法与ArrayList差不多
2.3 Set(接口)
- set是一种不包括重复元素的Collection,所以随机访问没有意义
- 允许null的存在但是仅有一个,和List一样
2.31 HashSet
注意点:
- 无序不重复(重复则保留之前的那一个),所以没有get()方法
- 允许null(只能一个),底层是hashMap,
- 支持Java的JDK1.8的遍历方法
System.out.println("hashset.size:" + hashSet.size());
- 支持迭代器
//调用iterator的方法
Iterator<Book> iterator = hashSet.iterator();
- 实现不同步,线程不安全
- 默认的初始容量16,负载因子(loadFactor)0.75(16 x 0.75 = 12 在容量达到12变成13时,开始扩容到原来的2倍,也就是16*2=32)
Book t1 = new Book("t1","Java从入门到放弃","12元");
Book t2 = new Book("t2","PHP从入门到放弃","44元");
Book t3 = new Book("t2","PHP从入门到放弃","44元");
HashSet<Book> hashSet = new HashSet<Book>();
hashSet.add(t1);
hashSet.add(t2);
hashSet.add(t3);
//没有重写前,
//重写后比较值,值相等就算重复
System.out.println("hashset.size:" + hashSet.size());
面试题:哪个集合元素不能重复?判断是否重复依据?如果让我们自己定义的类也去遵循一定的“业务标准”【重写equals和hashCode方法】
大致思想:
- 先判断hashCode()方法来确定元素的存储位置(也就是值是否相等),不等则认为不是同一个对象
- 相等则去调用equals方法判断(比较值),如果返回true,认为重复;否则不重复
源码再现:
3 Iterator迭代器
- hasNext();——boolean
- next();——E(泛型所定义的一个类型)
- while循环使用迭代(循环次数不固定)
- 支持泛型写法
- 迭代时不允许删除,否则报illegalStateException异常
iterator()
//以正确的顺序返回该列表中的元素的迭代器
ArrayList中使用iterator()
ArrayList<Book> arrayList = new ArrayList<Book>();
arrayList.add(t1);
Iterator<Book> itor1 = arrayList.iterator();
while (itor1.hasNext()) {
System.out.println(itor1.next().getName());
}
LinkedList中使用iterator()
LinkedList<Book> linkedList = new LinkedList<Book>();
linkedList.addFirst(t1);
Iterator<Book> itor2 = linkedList.iterator();
while (itor2.hasNext()) {
System.out.println(itor2.next().getName());
}
Vector中使用iterator()
Vector<Book> vector = new Vector<Book>();
vector.add(t1);
Iterator<Book> itor3 = vector.iterator();
while (itor3.hasNext()) {
System.out.println(itor3.next().getName());
}
例题:
考察hasNext查询和next的索引移动规律
ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
//返回值为Iterator接口
Iterator itor = list.iterator();
System.out.println(itor.hasNext());
System.out.println(itor.hasNext());
System.out.println(itor.hasNext());
System.out.println(itor.hasNext());
System.out.println(itor.next());
System.out.println(itor.next());
System.out.println(itor.next());
System.out.println(itor.hasNext());
System.out.println(itor.next());
数组里面只有3个元素,4个next会找到索引为3的元素,因为没有,所以报错
**hasNext()**只是查找,没有索引的增加
4 Map
4.1 HashMap(无序)
注意点:
- 是基于哈希表的实现的Map接口 的非同步实现
- 在以前的版本,HahMap采用的是数组+链表实现,JDK1.8 后 数组+链表+红黑树(平衡搜索二叉树) 实现
- 允许null值和null键
- 默认容量16,负(加)载因子0.75(内容达到160.75=12时会扩容到16 2倍=32)
- 不支持add()和addAll()
- 非线程安全,线程不同步
- set源码底层有HashMap的put方法
- get(K) put(K V) remove(K V) remove(K)
- key键不能重复,如果重复则后续会覆盖前一个值
hashMap.put(1, "大哥");
hashMap.put(1, "小哥");
- 但值可以重复
hashMap.put(1, "大哥");
hashMap.put(2, "大哥");
//得到keyset -> 所有key集合 set
System.out.println(hashMap.keySet());
//得到value结合values Collection
System.out.println(hashMap.values());
//键+值 -> 整体
System.out.println(hashMap.entrySet());
遍历方法
//遍历——entrySet
//object类型,如果是String类型的,因为类型不匹配,也不能转型(跟后面比较)
for (Object object : hashMap.entrySet()) {
System.out.println(object);
}
//遍历——key 迭代器
Set keySet = hashMap.keySet();
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
Object key = (Object) iterator.next();
System.out.println("it -> key" + key);
//通过key得到value
System.out.println("key -> value" + hashMap.get(key));
}
//遍历——key keyset
for (Object object : hashMap.keySet) {
System.out.println(object);
}
//遍历——value values
for (Object object : hashMap.values) {
System.out.println(object);
}
for (int i = 0; i < hashMap.size(); i++) {
System.out.println(hashMap.get(i));
}
//foreach jdk 1.8
hashMap。forEach(System.out::println);
4.2 TreeSet
注意点:
- 有序,按照自然顺序排序(字母则按字母顺序、数字按照大小)
ts.add("ane");
ts.add("")
- 实现(线程)不同步
5 自然排序
5.1 Arrays
支持内部外部比较器
Arrays类包含用于操作数组的各种方法(如排序和搜索),还包含一个静态工厂,可以将数组视为列表。
comparable内部比较器
- 类如果想【支持排序】,就要实现comparable接口,该接口称为对象的内部比较器
比如这边Integer就实现了Comparable接口
- 支持排序,但只能有一种排序逻辑,比较受限制
comparator外部比较器
- 可以使用外部比较器Comparator,灵活为类定义多种比较器 ,此时类本身不需要实现Comparable接口
Comparator接口方法:
在这里插入代码片
注意: 如果没有实现Comparable/Comparator会抛出ClassCastException异常
5.2 collections工具类
包含很多对集合的操作的静态方法
字段:list map set
支持内部外部比较器
内部比较器
//重写compareTo的方法
@Override
public int compareTo(Student o) {
// -1按照id升序(从小到大)
return this.age < o.age ? -1 : this.age==o.age ? 0:1;
}
public static void main(String[] args) {
Student s1 = new Student(200,"a",223);
Student s2 = new Student(100,"b",333);
Student s3 = new Student(300,"a",113);
Student[] array = {s1,s2,s3};
Arrays.sort(array);
for (Student student : array) {
System.out.println(student);
}
}
外部比较器
public static void main(String[] args) {
Teacher t1 = new Teacher(200, "a", 223);
Teacher t2 = new Teacher(100, "b", 333);
Teacher[] teachers = { t1, t2 };
//匿名内部类实现
//Arrays.sort(teachers,new IdComparator());
Arrays.sort(teachers,new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
// TODO Auto-generated method stub
return o1.getAge() < o2.getAge() ? -1 : o1.getAge() == o2.getAge() ? 0 : 1;
}
});
for (Teacher t : teachers) {
System.out.println(t);
}
}
//新建外部类实现
class IdComparator implements Comparator<Teacher> {
public int compare(Teacher o1, Teacher o2) {
// TODO Auto-generated method stub
return o1.getId() < o2.getId() ? -1 : o1.getId() == o2.getId() ? 0 : 1;
}
}
Collection和Collections有什么区别,Array和Arrays有什么区别?
collection | collections |
---|---|
接口 | 类 |
集合层次结构中,子接口有list,set | 提供了很多对集合操作的静态方法 |
add,clear,remove,size方法等 | Sort支持外部比较器reverse,copy,max,min, |
Array[数组类型]/理解成 | Arrays |
---|---|
引用类型,代指[] | 类 |
自己实现算法 | Sort提供很多操作数组的方法 |
Array类提供静态方法来动态创建和访问Java数组。在包Java.lang.reflect.Array |
线程同步
多个线程同时请求一个集合对象的时候,比如List.add(),数据可能会丢失(ArrayList、LinkList、HashSet、HashMap)
map本身不是线程同步,但是他的ConcurrentHashMap是synochromnzied,支持线程同步。
泛型
List<String> list = new List();
//使用泛型
list<E>
//泛型的定义