javaSE-day06(集合进阶)

发布时间 2023-03-28 14:21:32作者: 王小子

异常

我们调用一个方法时,经常一部小心就出异常了,然后在控制台打印一些异常信息。其实打印的这些异常信息,就叫做异常。
因为写代码时经常会出现问题,Java的设计者们早就为我们写好了很多个异常类,来描述不同场景下的问题。而有些类是有共性的所以就有了异常的继承体系

public class Demo9 {
	// JVM 调用main方法。
	// JVM 处理异常的方式,简单粗暴!  直接将程序停下来,然后给你打印错误信息。
	public static void main(String[] args) {
		// StackOverflowError: 栈内存溢出。
		// main(new String[0]);
		String s = "2020-5-5";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy。MM-dd");
		// 就是在编译阶段给我爆出的错误。
		// 必须解决,如果不解决,程序无法运行。
		try {
			// 可能出现异常的代码
			// 有没有一定会出现问题的代码
		   /* Date parse = sdf.parse(s);  // 解析字符串,成为一个Date对象。    方法所需的东西:1. 传入的字符串时间。  2. 解析的模版
			// new ParseException();
			System.out.println(parse);*/
			int[] arr = {};  // new ArrayIndexOutOfBoundsException();
			System.out.println(arr[9]);
		} catch (Exception e) {  // 捕获异常对象。 Exception e = new ParseException();  多态
			// 异常的处理逻辑
			// 写入日志。
			System.out.println("有问题了!不管!");
		} finally {
			// 一定会执行的代码块。

		}
		System.out.println("程序继续执行。");

		// 编译异常:为了提醒调用者,注意该问题。
	}
}


public class Demo10 {
	// JVM 调用main方法。
	// JVM 处理异常的方式,简单粗暴!  直接将程序停下来,然后给你打印错误信息。
	public static void main(String[] args) {
	   /* try {
		   // IO流读写文件。
			//xxxxx   有没有可能出现问题?
			// f.close();
		} catch (Exception e) {

			// f.close();
		} finally {
			// 一定会执行的代码块。
			// f.close();
		}
		System.out.println("程序继续执行。");*/
		System.out.println(get());
	}

	public static int get(){
		try {
			// IO流读写文件。
			//xxxxx   有没有可能出现问题?
			// f.close();
			System.out.println(111);
			return 1;
		} catch (Exception e) {
			System.out.println(222);
			return 2;
			// f.close();
		} finally {
			// 一定会执行的代码块。
			// f.close();
			System.out.println(333);
			// return 3;
		}
	}
}


public class Demo11 {
public static void main(String[] args) throws Exception {
    // 编译异常: 必须处理的异常   继承Exception的子类异常。
    // 运行异常: 运行过程中,才有可能出错的异常  继承RuntimeException的子类异常。
    // method();
    show();

    // throws: 抛出异常,解决方法内部出现的问题,给调用者处理
    // throw: 在方法内部制造异常异常。
    //   调用方法者,传入的参数不满足要求。
    // 如果制造的是运行异常,可以不用抛出
    // 如果制造的是编译异常,则必须抛出

    int[] arr = {-1,-1,-1,-1};
    System.out.println(getValue(arr, 10));
}

// 功能:获取数组中,指定索引的元素
public static int getValue(int[] arr, int index) throws Exception{
    if(index >= 0 && index < arr.length){
        return arr[index];
    }
    // System.out.println("你有病啊,越界了!");
    // 此时方法内部,返回任何结果都不合适。
    // 只能制造一个异常,告诉调用者。
    // return -1;
    throw new Exception("你有病啊,越界了!");
}

public static void method() throws ParseException {
    // 在方法中,没办法处理的问题,则抛给调用者处理。
    // 抛出编译异常,才能起到提醒作用。

    String s = "2020-5-5";
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy。MM-dd");
    sdf.parse(s);

}

public static void show() throws RuntimeException {
    // 抛出运行异常,对于调用者来说,没有任何意义。
}
}

集合

集合是一种容器,用来装数据的,类似于数组,但集合的大小可变,开发中也非常常用。
image


image

image
Collection是单列集合的祖宗,它规定的方法(功能)是全部单列集合都会继承的。
常见方法:
image

遍历方式
迭代器:
image

public class Demo2 {
	public static void main(String[] args) {
		Collection<String> list = new ArrayList<>();
		list.add("aaa");
		list.add("ccc");
		list.add("bbb");
		list.add("fff");
		list.add("eee");
		// 元素存取有序,可重复
		System.out.println(list);

		// 迭代器:就是另一种遍历的方式。
		Iterator<String> it = list.iterator();  // 获取迭代器对象
		// hasNext(): 判断是否还有元素
		while(it.hasNext()){
			// next() 将元素取出
			String next = it.next();
			/*if(next.equals("bbb")){
				// list.remove(next);
				it.remove();
			}*/
			System.out.println(next);
		}
		// System.out.println(list);
		/*
			ConcurrentModificationException: 并发修改异常
				不能在使用迭代器遍历集合的同时,使用集合对象去操作(增加、删除)集合中的元素的个数。
		 */
	}
}

增强for循环/foreach:

格式:
for (元素的数据类型 变量名 : 数组或者集合) {       
}
增强for可以用来遍历集合或者数组。
增强for遍历集合,本质就是迭代器遍历集合的简化写法。
public class Demo3 {
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("ccc");
    list.add("bbb");
    list.add("fff");
    list.add("eee");
    // 元素存取有序,可重复
    System.out.println(list);

    // 增强for   list.for
    // 增强for的底层,就是迭代器。
    // ConcurrentModificationException: 并发修改异常
    // 语法糖。   糖衣。
    for (String s : list) {
        System.out.println(s);
    }
    System.out.println(list);

    int[] arr = {11,22,33,44};
    for (int num : arr) {
        System.out.println(num);
    }
}
}

Lambda表达式遍历集合:

image

public class Demo4 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("aaa");
		list.add("ccc");
		list.add("bbb");
		list.add("fff");
		list.add("eee");
		// 元素存取有序,可重复
		System.out.println(list);

		for (int i = 0; i < list.size(); i++) {
			String s = list.get(i);
			System.out.println(s);
		}

		// Consumer:消费类型接口
		// Function: 转换类型接口
		// Supplier: 生成类型接口
		// Predicate: 判断类型接口

		// 普通for 增强for  迭代器   转数组
		list.forEach(s -> System.out.println(s));
		list.forEach(System.out::println);
	}
}

image

List集合

image

List集合的特有方法
List集合因为支持索引,所以多了很多与索引相关的方法,当然,Collection的功能List也都继承了。
image

List集合支持的遍历方式:

image

不同集合底层采用的数据结构不同,应用的场景不同


ArrayList:

image

所以ArrayList的适用场景为:
image

image

LinkedList:

image

LinkedList集合的底层原理:

image

LinkedList新增

image

LinkedList应用场景

image


Set集合

特点
image

哈希值

image


HashSet集合底层原理:
基于哈希表实现
哈希表是一种增删改查数据,性能都较好的数据结构
哈希表:
JDK8之前,哈希表=数组+链表
image

JDK8开始,哈希表=数组+链表+红黑树
image

如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法

LinkedHashSet:
linkedhashset底层原理
依然是基于哈希表(数组、链表、红黑树)实现的。
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
image


TreeSet
特点:不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)
底层是基于红黑树实现的排序。
注意!
1.对于数值类型:Integer , Double,默认按照数值本身的大小进行升序排序。
2.对于字符串类型:默认按照首字符的编号升序排序。
3.对于自定义类型如Student对象,TreeSet默认是无法直接排序的。

自定义排序规则:

TreeSet集合存储自定义类型的对象时,必须指定排序规则,支持如下两种方式来指定比较规则。

方式一
让自定义的类(如学生类)实现Comparable接口,重写里面的compareTo方法来指定比较规则。

方式二
通过调用TreeSet集合有参数构造器,可以设置Comparator对象(比较器对象,用于指定比较规则。

两种方式中,关于返回值的规则:
如果认为第一个元素 > 第二个元素 返回正整数即可。
如果认为第一个元素 < 第二个元素返回负整数即可。
如果认为第一个元素 = 第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。
注意:如果类本身有实现Comparable接口,TreeSet集合同时也自带比较器,默认使用集合自带的比较器排序!


最后:
image