集合应用
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)结果展示
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中的歌异常类名是一种平级关系
如果出现父子关系,那么这种将最大的异常写在最后
c.jdk7以后出现了一个新的捕获异常的方式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("代码可能会有问题,但具体不知道"); } } }
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(); } } }
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(这种情况只能子类中进行捕获异常);