【JavaSE学习笔记】集合应用_Collectons工具,模拟斗地主,异常

集合应用

A.Collections工具

1)Collections和Collection的区别?

Collection:集合:顶层次的一个根接口,有两个子接口:List,Set

Collections:对集合操作的工具类,具体的类:它针对集合进行操作

2)功能

public static void sort(List list):默认的自然排序,将集合中的元素升序排序

import java.util.ArrayList;
import java.util.Collections;

public class Demo01 {
	public static void main(String[] args) {
		// 创建一个集合对象
		ArrayList al = new ArrayList();

		// 添加元素
		al.add(20);
		al.add(19);
		al.add(21);
		al.add(18);
		al.add(17);
		al.add(16);

		// 排序前
		System.out.println(al);// [20, 19, 21, 18, 17, 16]
		// 自然排序后
		Collections.sort(al);
		System.out.println(al);// [16, 17, 18, 19, 20, 21]
	}
}

public static int binarySearch(List> list,T key):二分查找搜索法:key:查找的元素

二分法必须是有序集合

import java.util.ArrayList;
import java.util.Collections;

public class Demo01 {
	public static void main(String[] args) {
		// 创建一个集合对象
		ArrayList al = new ArrayList();

		// 添加元素
		al.add(20);
		al.add(19);
		al.add(21);
		al.add(18);
		al.add(17);
		al.add(16);

		// 排序前
		System.out.println(al);// [20, 19, 21, 18, 17, 16]
		// 自然排序后
		Collections.sort(al);
		System.out.println(al);// [16, 17, 18, 19, 20, 21]

		int i = Collections.binarySearch(al, 18);
		System.out.println(i);// 2
	}
}

public static void reverse(List list):反转功能

import java.util.ArrayList;
import java.util.Collections;

public class Demo01 {
	public static void main(String[] args) {
		// 创建一个集合对象
		ArrayList al = new ArrayList();

		// 添加元素
		al.add(20);
		al.add(19);
		al.add(21);
		al.add(18);
		al.add(17);
		al.add(16);

		// 排序前
		System.out.println(al);// [20, 19, 21, 18, 17, 16]
		// 自然排序后
		Collections.sort(al);
		System.out.println(al);// [16, 17, 18, 19, 20, 21]
		
		// 反转后
		Collections.reverse(al);
		System.out.println(al);// [21, 20, 19, 18, 17, 16]
	}
}

public static void shuffle(List list):随机置换,打乱顺序

import java.util.ArrayList;
import java.util.Collections;

public class Demo01 {
	public static void main(String[] args) {
		// 创建一个集合对象
		ArrayList al = new ArrayList();

		// 添加元素
		al.add(20);
		al.add(19);
		al.add(21);
		al.add(18);
		al.add(17);
		al.add(16);

		// 排序前
		System.out.println(al);// [20, 19, 21, 18, 17, 16]
		// 自然排序后
		Collections.sort(al);
		System.out.println(al);// [16, 17, 18, 19, 20, 21]
		
		// 置换后
		Collections.shuffle(al);
		System.out.println(al);// [20, 19, 18, 21, 17, 16]
	}
}

3)问题:

如果用Collections集合工具类对自定义对象同时进行自然排序和比较器排序

哪个起作用?

答:比较器起排序主要作用

B.模拟斗地主(集合完成)

1)模拟斗地主洗牌、发牌、看牌、发牌是有序的

有序(3,4,5,6,7,8,9,10,J,Q,K,A,2,小王,大王)

2)思路:

1.创建HashMap集合,创建ArrayList集合,存储编号

2.装牌:给集合中添加编号,以及对应的牌(点色和花色数组遍历拼接)

将编号添加到ArrayList中

3.洗牌:洗的是编号(Collections.shuffle()只能对List集合进行置换,所以必须单独建一个ArrayList集合)

4.发牌:发的也是编号,为了保证牌是有序的,所有应该用TreeSet集合

5.看牌:遍历TreeSet编号,在HashMap中遍历对应的值

3)代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;

public class PokerDemo {
	public static void main(String[] args) {
		// 1)创建HashMap集合:编号和牌
		HashMap hm = new HashMap();

		// 创建ArrayList集合:存储编号
		ArrayList al = new ArrayList();

		// 2)装牌
		// 创建花色数组(黑红梅方)
		String[] colors = { "♠", "♥", "♣", "♦" };
		// 创建点数数组(从小到大)
		String[] numbers = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2" };
		// 给牌进行编号,从0开始
		int index = 0;
		// 给牌拼接并编号
		// 先点数从小到大的顺序
		for (String number : numbers) {
			// 再花色按照黑红梅方的顺序
			for (String color : colors) {
				// 拼接扑克(花色+点数)
				String poker = color.concat(number);
				// 添加到集合中(编号, 扑克)
				hm.put(index, poker);
				// 将编号添加到ArrayList
				al.add(index);
				// 编号+1
				index++;
			}
		}

		// 不要忘了添加大王小王
		hm.put(index, "小王");
		al.add(index);
		index++;
		hm.put(index, "大王");
		al.add(index);

		// 3)洗牌:洗的是编号
		Collections.shuffle(al);

		// 4)发牌(发的也是编号,保证有序,用TreeSet接收)
		// 三个玩家,一个底牌
		TreeSet player1 = new TreeSet();
		TreeSet player2 = new TreeSet();
		TreeSet player3 = new TreeSet();
		TreeSet diPai = new TreeSet();

		for (int i = 0; i < al.size(); i++) {
			// 判断
			// 最后三张是底牌
			if (i >= al.size() - 3) {
				// 可以直接写diPai.add(i),最好写al.get(i)
				// i是角标,get(i)才是值
				diPai.add(al.get(i));
			} else if (i % 3 == 0) {
				// 被3整除的发给第1个人
				player1.add(al.get(i));
			} else if (i % 3 == 1) {
				// 被3整除余1的发给第2个人
				player2.add(al.get(i));
			} else if (i % 3 == 2) {
				// 被3整除余2的发给第3个人
				player3.add(al.get(i));
			}
		}

		// 5)看牌(遍历TreeSet集合获取到对应的编号,那对应的编号在HashMap中找牌)
		System.out.println("*********************************欢迎来到欢乐斗地主*********************************");
		lookPoker("玩家1", player1, hm);
		lookPoker("玩家2", player2, hm);
		lookPoker("玩家3", player3, hm);
		lookPoker("底牌", diPai, hm);

	}

	public static void lookPoker(String name, TreeSet ts, HashMap hm) {
		System.out.print(name + "的牌是:");
		// 遍历TreeSet集合的编号
		for (Integer key : ts) {
			// 获取到编号,通过get(key),获取hm中的牌
			String s = hm.get(key);
			System.out.print(s + "  ");
		}
		System.out.println();
	}
}

4)结果展示

【JavaSE学习笔记】集合应用_Collectons工具,模拟斗地主,异常_第1张图片

C.异常

1)程序出现问题

举例:

今天天天很好,班长骑车去旅游...

问题1:他在骑车的过程中,路塌陷了,不能骑行了;不可抗力的问题:严重问题!

问题2:他在骑行的过程中,自行车没气了;本来应该在骑行之前首先检查的问题!

问题3:山路两边是平坦的,中间是石子,班长非在中间骑,属于自身问题:no zuo no die

2)程序的异常:Throwable

error:这种问题是一个严重问题

一般出现这种问题,需要一起解决(程序员只能避免严重问题),比如:内存溢出(OutOfMemory);

Exception:异常:

编译时期异常:如果程序员不管这个,根本没办法运行,需要解决

运行时期异常:只要不是编译时期异常,都属于异常异常;一般情况,是因为们的代码不够严谨.

3)异常的描述:

哪一个包下的异常,并且将报错的信息打印控制台(出现错误的位置)

格式:(finally可省略)

try{

     可能出现问题的代码;
}catch(异常类名 变量名){

      输出语句;
}fianll{

      释放资源;
}

public class Demo01 {
	public static void main(String[] args) {
		int a = 10;
		int b = 0;

		// a / b,除数为0,抛出此类的一个实例。(运行时期异常!)
		System.out.println(a / b);
		// java.lang.ArithmeticException: / by zero
	}
}

4)如果一个程序出现异常了,他会将异常的信息打印在控制台

运行时期异常如何解决:

try...catch一个异常

public class Demo01 {
	public static void main(String[] args) {
		int a = 10;
		int b = 0;

		try {
			System.out.println(a / b);
		} catch (ArithmeticException ae) {
			System.out.println("除数不能为0");
		}
	}
}
两个异常

a.一个一个去try...catch

实际开发中:捕获异常时:给具体的异常类,不要随意使用Exception

public class Demo01 {
	public static void main(String[] args) {
		int a = 10;
		int b = 0;

		try {
			System.out.println(a / b);
		} catch (ArithmeticException ae) {
			System.out.println("除数不能为0");
		}

		int[] arr = new int[3];
		try {
			System.out.println(arr[3]);
		} catch (ArrayIndexOutOfBoundsException aie) {
			System.out.println("访问了不存在的索引");
		}
	}
}

b.一个try,多个catch

捕获异常:catch中的歌异常类名是一种平级关系

                  如果出现父子关系,那么这种将最大的异常写在最后

public class Demo01 {
	public static void main(String[] args) {
		int a = 10;
		int b = 0;

		int[] arr = new int[3];
		try {
			System.out.println(a / b);
			System.out.println(arr[3]);
		} catch (ArithmeticException ae) {
			System.out.println("除数不能为0");
		} catch (ArrayIndexOutOfBoundsException aie) {
			System.out.println("访问了不存在的索引");
		} catch (Exception e){
			// 这个类就要放在最后面
			System.out.println("代码可能会有问题,但具体不知道");
		}
	}
}
c.jdk7以后出现了一个新的捕获异常的方式

try{

       可能出现问题的代码

} catch (异常类名1 | 异常类名2 | 异常类名3  变量名){

}


注意:弊端:开发中,可能会出现同类型问题,需要捕获同一个异常信息

public class Demo01 {
	public static void main(String[] args) {
		int a = 10;
		int b = 0;

		int[] arr = new int[3];
		
//		try {
//			System.out.println(a / b);
//			System.out.println(arr[3]);
//		} catch (ArithmeticException | ArrayIndexOutOfBoundsException e){
//			System.out.println("捕获到了异常!");
//		}
		
		try {
			System.out.println(a/b);
			System.out.println(arr[3]);
		} catch (Exception e) {
			System.out.println("捕获到了异常!");
		}
	}
}

5)java程序中编译时期异常和运行时期异常的区别

编译时期异常:需要我们去处理,否则编译不通过,显示处理

运行时期异常:无需显示处理,也可以像编译时期异常处理一样

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01 {
	public static void main(String[] args) {
		String s = "2017-10-1";
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM,dd");
		
		//开始解析
		try {
			Date d = sdf.parse(s);
			System.out.println(d);
		} catch (ParseException pe) {
			System.out.println("解析出问题了");
		}
	}
}

使用捕获异常:try...catch这个格式时候

如果try里面的代码出现问题了,jvm会生成异常对象

然后抛出来和catch中描述的这个异常信息进行匹配,判断

如果一致,这里会输出处理语句(输出语句)

6)异常类的一些方法

public String getMessage():返回的是一个异常的消息字符串

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01 {
	public static void main(String[] args) {
		String s = "2017-10-1";

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM,dd");

		// 开始解析
		try {
			Date d = sdf.parse(s);// jvm产生一个对象 :ParseException
		} catch (ParseException pe) {// ParseException e = new ParseException ();
			String str = pe.getMessage();
			System.out.println(str);// Unparseable date: "2017-10-1"
		}
	}
}

public String toString():返回的是一个简单的表述信息

当前类对象 name:全路径名 : 空格 + getMessage()

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01 {
	public static void main(String[] args) {
		String s = "2017-10-1";

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM,dd");

		// 开始解析
		try {
			Date d = sdf.parse(s);// jvm产生一个对象 :ParseException
		} catch (ParseException pe) {// ParseException e = new ParseException ();
			String str = pe.toString();
			System.out.println(str);// java.text.ParseException: Unparseable date: "2017-10-1"
		}
	}
}

public void printStackTrace():捕获异常信息,以及出现的具体位置在哪里

返回的是void类型,直接在控制台的!

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01 {
	public static void main(String[] args) {
		String s = "2017-10-1";

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM,dd");

		// 开始解析
		try {
			Date d = sdf.parse(s);// jvm产生一个对象 :ParseException
		} catch (ParseException pe) {// ParseException e = new ParseException ();
			pe.printStackTrace();
		}
	}
}
【JavaSE学习笔记】集合应用_Collectons工具,模拟斗地主,异常_第2张图片

7)处理异常的第二种方式

throws:抛出异常

当我们处理异常,如果没有一些权限处理异常,那我们就不处理了

通过开发工具,提示抛出异常,这个时候就可以使用throws

推荐不建议在main方法抛出

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo01 {
	public static void main(String[] args) {
		try {
			method();// 方法有异常,调用的时候也要处理异常
		} catch (ParseException e) {
			e.printStackTrace();
		}
	}

	// 该方法中的异常属于编译时期异常:告诉开发者,你注意了,我有问题!
	public static void method() throws ParseException {
		String s = "2017-8-8";

		// 创建对象
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
		Date d = sdf.parse(s);// 编译时期异常
		System.out.println(d);
	}
}

8)面试题:

throws和throw的区别?(100%会问到!)

throws:一般用在方法声明上

抛出的是一个异常类名,可以抛出多个异常,中间用逗号隔开

throws表示抛出异常,这段代码可能会抛出异常( 指的是抛出异常的可能性)

一般情况:throws用的比较多

throw:一般在方法中进行抛出

抛出的是一个异常对象(匿名对象的方式)

throw表示抛出异常:肯定的抛出异常(具体异常),走到这块代码,一定会执行throw中的异常

在语句中进行处理

public class Demo02 {
	public static void main(String[] args) {
		method();
	}

	public static void method(){
		int a = 10;
		int b = 0;
		if (b == 0) {
			throw new ArithmeticException();// 代码走到这块:表示一定会执行这个异常
		} else {
			System.out.println(a / b);
		}
	}
}

9)执行代码的顺序

try{

可能出现错误的代码

}catch(异常类名 变量名){

处理异常;

}finally{

释放资源;

}

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo03 {
	public static void main(String[] args) {
		String s = "2017-8-8";

		SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");

		Date d = null;

		try {
			d = sdf.parse(s);
		} catch (ParseException e) {
			e.printStackTrace();
			System.exit(0);// jvm退出
		} finally {
			System.out.println("必须执行!释放资源!除非前面有System.exit(0)");
		}
	}
}
注意:

finally中的代码是一定会执行的,一般用在IO流中和数据库中;
如果在执行finally中的代码之前,JVMjava虚拟机退出了,那么finally中的释放资源是不会执行的

10)面试题

final,finalize,finally三者之间的区别?(100%问到)

final:最终的,终态的

final修饰类:该类不能被继承

final修饰成员变量:该变量是自定义常量

final修饰成员方法:该方法不能被重写

finalize:和垃圾回收期有关系:运行垃圾回收器的方法:gc().调用gc()

实质是调用了通过重写了Object中的finalize方法

finally:出现在IO流中或者数据库中,用来释放资源的!

11)面试题

如果catch有return语句,finally中的会执行吗?

如果会,是在return前执行还是在return后执行?

会执行finally中的代码,是在return前执行

确切的说是在代码中间执行!

public class Demo04 {
	public static void main(String[] args) {
		System.out.println(getInt());
	}

	public static int getInt() {
		int a = 10;
		try {
			a = 20;
			System.out.println(a / 0);
		} catch (Exception e) {
			a = 30;
			return a;
			/**
			 * 当代码走到这一块,a = 30 ; return a ====>return 30 ,这里面形成了一回路径,
			 * 但是,一看这里有finally,所以会执行finally中的代码,a =40 ,
			 * 最终返回return a====>return前面的语句:30
			 * */
		} finally {
			a = 40;
		}
		return a;
	}
}

12)自定义异常类

有时候在实际开发中,可能会需要自己定义一个异常类;不是说起以类名就是可以当作异常类,

必须自定义的类继承Exception或者RuntimeException,那么这样的类,才是自己定义的异常类

// 自定义异常类
public class MyException extends Exception {

	public MyException() {
		super();
	}

	public MyException(String message) {
		super(message);
	}

}

// Teacher
public class Teacher {
	public static void check(int score) throws MyException {
		// 录入学生成绩,0-100之间
		if (score > 100 && score < 0) {
			System.out.println("成绩必须在0~100之间!");
		} else {
			System.out.println("成绩符合我们的规则!");
		}
	}
}

import java.util.Scanner;

// 自定义异常的测试
public class StudentDemo {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		System.out.println("请输入成绩:");
		int score = sc.nextInt();
		
		try {
			Teacher.check(score);
		} catch (MyException e) {
			e.printStackTrace();
		}
	}
}

 异常类中的注意事项:

a.子类重写父类中的方法,如果父类中方法抛出一个异常

那么子类重写父类该方法时抛出异常,要么跟父类中异常保持一致,要么要是他的异常类的子类

b.如果被重写的方法,没有抛出异常,那么子类重写这个方法

也不能抛出异常,不能throws,只能try...catch(这种情况只能子类中进行捕获异常);


你可能感兴趣的:(JavaSE)