课程 Java面向对象程序设计 实验名称 异常处理机制、集合框架
班级 13级计三 学号 10503 姓名
一、实验目的
掌握面向对象程序设计技术
二、实验环境
1、微型计算机一台
2、WINDOWS操作系统,Java SDK,Eclipse开发环境
三、实验内容
1、Java异常处理机制涉及5个关键字:try、catch、finally、throw、throws,请理解每个关键字的作用,并在编写程序,使用运用这5个关键字,观察效果。
2、设计学生类(是一个javaBean),包含年龄和姓名(均私有)。
3、Java常用的集合类有:HashSet、TreeSet(红黑树)、ArrayList、Stack、HashMap(用学生类的年龄作为键值)、Properties,请编写程序,分别使用运用这些集合类,来存储学生类对象。
4、请问java中有没有优先队列实现类,如果有,请编写程序,演示该类的使用。
四、实验步骤和结果
1、Java异常处理机制涉及5个关键字:try、catch、finally、throw、throws,请理解每个关键字的作用,并在编写程序,使用运用这5个关键字,观察效果。
(1)try和catch
try的意思是测试它所包含的代码是否会发生异常,而catch 的意思就是在异常发生时就抓住它,并进行相应的处理,使程序不受该异常的影响从而继续执行下去。
它们通常使用的格式如下:
Try{ //代码段(可能会发生异常的代码) } catch (异常类型 ex) { //对异常进行处理的代码段 } //代码段 |
测试代码(MoreCatchDemo.java)如下所示:(注意:当有多个catch,在安排catch语句的顺序时,首先应该捕获子类异常,然后再捕获父类异常)
import java.util.InputMismatchException; import java.util.Scanner; public class MoreCatchDemo { /*** @param args */ public static void main(String[] args) { Scanner in=new Scanner(System.in); try { System.out.println("请输入第一个学期的总学时:"); int totalTime=in.nextInt();//总学时 System.out.println("请输入第一个学期的总课程:"); int totalCourse=in.nextInt();//课程总数 System.out.println("第一学期各个课程的平均学时为:"+totalTime/totalCourse); } catch (InputMismatchException e1) { // TODO: handle exception System.out.println("输入不为数字!"); }catch (ArithmeticException e2) { // TODO: handle exception System.out.println("课程数目不能为0!"); }catch (Exception e) { // TODO: handle exception System.out.println("发生错误:"+e.getMessage()); } System.out.println("我是catch后面的代码。"); } } |
(2) finally
在某些特定的情况下,不管是否有异常发生,总是要求某些特定的代码必须被执行,这就需要用到finally 关键字。
测试代码(FinallyDemo.java)如下所示:
public class FinallyDemo { /** * @param args */ public static void main(String[] args) { System.out.println("请打开数据连接……"); try { System.out.println("执行查询操作"); System.out.println("执行修改操作"); int i=12/0; System.out.println("执行添加操作"); System.out.println("执行删除操作"); } catch (Exception e) { // TODO: handle exception System.out.println("除零出错!"); e.printStackTrace(); } finally{ System.out.println("请关闭数据连接……"); } } } |
(3)throw
throw 语句用来明确地抛出一个“异常”。需要注意的是,用户必须得到一个Throwable类或者其他子类产生的实例句柄,通过参数传到catch字句,或者用 new语句来创建一个实例。throw 总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,throw后必须抛出一个Throwable类的实例。
测试代码(ThrowDemo.java)如下所示:
public class ThrowDemo { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub int number=0; try { number=Integer.parseInt(args[0]); } catch (Exception e) { // TODO: handle exception throw new ArrayIndexOutOfBoundsException("数组越界!"); //System.out.println("非法的数字"); } System.out.println("你输入的数字为:"+number); } } |
(4)throws
Throws 用来声明一个方法可能会抛出的所有异常,它跟在方法签名的后面。
若这个方法可以引发异常,而它本身并不对该异常进行处理,那么该方法必须将这个异常抛给调用者以使程序能够继续执行下去。如果有多个异常,则使用逗号将其分开。
测试代码(ThrowsDemo.java)如下所示:
public class ThrowsDemo { /** * @param args*/ public static void main(String[] args) { testThrows(args); } private static void testThrows(String[] tmp) { try { createThrow(tmp); } catch (Exception e) { System.out.println("来自createThrow方法的异常"); } } //抛出可能的异常 private static void createThrow(String[] tmp) throws Exception { int number=3; System.out.println("你输入的数字为:"+number+‘\n‘); number=Integer.parseInt(tmp[0]); System.out.println("你输入的数字为:"+number); } } |
(5)throw和throws语句的组合使用
一般都需要throw和throws语句的组合使用,就是在捕获异常后,抛出一个明确的异常给调用者。
测试代码(ThrowAndThrowsDemo.java)如下所示:
|
2、设计学生类(是一个javaBean),包含年龄和姓名(均私有)。
测试代码(StudentJavaBean.java)如下所示:
//StudentJavaBean: //1.有一个无参的公共的构造方法 //2.有属性,属性最好定义为私有的。 //3.有与属性对应的get、set存取方法 //public class StudentJavaBean implements Comparable { //在实现TreeSetTest中,这里接口是必须的 public class StudentJavaBean { private int age; private String name; private Integer score; public StudentJavaBean() { } //无参构造方法 public StudentJavaBean(int age, String name,int score) { super(); this.age = age; this.name = name; this.score=score; } //与属性对应的get、set存取方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getScore() { return score; } public void setScore(Integer score) { this.score = score; } //要显示Student的信息,必须重写toString()方法 public String toString() { return "StudentJavaBean [age=" + age + ", name=" + name +",score="+ score+ "]"; } |
3、Java常用的集合类有:HashSet、TreeSet(红黑树)、ArrayList、Stack、HashMap(用学生类的姓名作为键值)、Properties,请编写程序,分别使用运用这些集合类,来存储学生类对象。
(1)HashSet
测试代码(HashSetTest.java)如下所示:
import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; public class HashSetTest { /** @param args */ public static void main(String[] args) { // TODO Auto-generated method stub HashSet hs=new HashSet(); hs.add(new StudentJavaBean(19,"张三",80)); hs.add(new StudentJavaBean(18,"李四",90)); hs.add(new StudentJavaBean(20,"黄七",85)); hs.add(new StudentJavaBean(17,"王五",95)); hs.add(new StudentJavaBean(21,"赵六",88)); Iterator it=hs.iterator();//获取集合迭代器 while (it.hasNext()) { System.out.println(it.next());//HashSet不保存元素加入顺序的特征 } } } |
(2)TreeSet
测试代码(TreeSetTest.java)如下所示:
import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.*; public class TreeSetTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Set<StudentJavaBean> ts=new TreeSet<StudentJavaBean>(); StudentJavaBean stu1=new StudentJavaBean(18,"张三",78); StudentJavaBean stu2=new StudentJavaBean(23,"李四",79); StudentJavaBean stu3=new StudentJavaBean(32,"王五",80); StudentJavaBean stu4=new StudentJavaBean(21,"赵六",87); StudentJavaBean stu5=new StudentJavaBean(18,"黄七",89); ts.add(stu3); ts.add(stu4); ts.add(stu1); ts.add(stu2); //ts.add(null);//不可以有null ? 会出错!! Iterator it=ts.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } |
同时,Student类要实现一个 Comparable接口,
修改之后代码如下:
public class StudentJavaBean implements Comparable {//在实现TreeSetTest中,这里接口是必须的 //public class StudentJavaBean { private int age; private String name; private Integer score; public StudentJavaBean() { } //无参构造方法 public StudentJavaBean(int age, String name,int score) { super(); this.age = age; this.name = name; this.score=score; } //与属性对应的get、set存取方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getScore() { return score; } public void setScore(Integer score) { this.score = score; } //要显示Student的信息,必须重写toString()方法 public String toString() { return "StudentJavaBean [age=" + age + ", name=" + name +",score="+ score+ "]"; } //在Java规范要求中,如果用户重写了equals()方法,就一定要重写hashCode()方法 //两个对象进行equals比较时,如果返回true,那么它们的hashCode要求返回相等的值 public int hashCode() { return age*name.hashCode(); } //HashSet 中加入的对象需要重写hashCode()和equals()方法 public boolean equals(Object o) { StudentJavaBean s=(StudentJavaBean) o; return age==s.age && name.equals(s.name); } //“让StudentJavaBean类实现Comparable接口” //因为要实现 Comparable接口,所以要重写comparaTo(object o)方法 //判断执行comparaTo方法的Student对象与传入的对象按排序的条件相比, //是大于、小于还是等于传入的对象 public int compareTo(Object o) { StudentJavaBean s=(StudentJavaBean) o; if (s.getAge() < this.getAge()) return 1; else if(s.getAge() == this.getAge()) return 0; else return -1; } //其实Integer 已经实现了Comparable接口,所以这里的compareTo方法中的代码还可以这样写: // public int comparaTo(Object o) { // StudentJavaBean s=(StudentJavaBean )o; // return s.age.compareTo(this.age);// } |
自定义比较器的代码(SelfTreeSetTest.java)如下:
import java.util.*; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; import java.util.LinkedHashSet; import java.util.Comparator; //学生年龄比较器 //下面这个借口指明参与比较的两个对象是学生类 class StudentAgeComparator implements Comparator<StudentJavaBean>{ public int compare(StudentJavaBean o1, StudentJavaBean o2) { // TODO Auto-generated method stub int i=o2.getAge() - o1.getAge(); return i; }} //学生成绩比较器 class StudentScoreComparator implements Comparator<StudentJavaBean> { public int compare(StudentJavaBean o1, StudentJavaBean o2) { int i=(int)(o2.getScore() - o1.getScore()); return i; }} public class SelfTreeSetTest { public static void main(String[] args) { // TODO Auto-generated method stub //创建TreeSet对象时选择比较器 //Set<StudentJavaBean> ts=new TreeSet<StudentJavaBean>(new StudentAgeComparator()); //上面是选择年龄比较器,下面是选择分数比较器 Set<StudentJavaBean> ts=new TreeSet<StudentJavaBean>(new StudentScoreComparator()); StudentJavaBean stu1=new StudentJavaBean(18,"张三",99); StudentJavaBean stu2=new StudentJavaBean(19,"李四",95); StudentJavaBean stu3=new StudentJavaBean(20,"王五",90); StudentJavaBean stu4=new StudentJavaBean(21,"赵六",94); ts.add(stu3); ts.add(stu4); ts.add(stu1); ts.add(stu2); Iterator it=ts.iterator(); while (it.hasNext()) { System.out.println(it.next()); } }} |
(3)ArrayList
测试代码( ListDemo.java)如下所示:
import java.awt.List; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class ListDemo { /** * @param args */ public static void main(String[] args) { Collection c1=new ArrayList(); c1.add(new Student(20,"张三")); Student c3=new Student(22,"王五"); c1.add(c3); c1.add(new Student(19,"黄七")); System.out.println("c1:"+c1); Collection c2=new ArrayList(); c2.addAll(c1);//将集合c1添加到c2集合对象中的操作 System.out.println("c2:"+c2); c2.remove(c3);//删除一个学生 System.out.println("c2:"+c2); c2.add("hello");//添加 System.out.println("c2:"+c2); Iterator it=c2.iterator();//下面介绍迭代器接口 while (it.hasNext()) { //用迭代器进行迭代(遍历)操作 Object obj=it.next(); //取出的元素类型为Object类型 System.out.println("Iterator遍历c2 "+obj+"\t"); } } } |
(4)Stack
测试代码(ThrowAndThrowsDemo.java)如下所示:
import java.util.Stack; public class StackDemo { /** * @param args */ public static void main(String[] args) { Stack stk=new Stack();//创建一个空Stack stk.push(new Student(19,"张三")); stk.push(new Student(20,"李四")); stk.push(new Student(22,"王五")); stk.push(new Student(17,"赵六")); System.out.println("stk="+stk); //把Stack当作Vector看待 stk.addElement(new Student(18,"黄七")); System.out.println("第三个学生是:"+stk.elementAt(2)); System.out.println("移出栈的顺序是:"); while (!stk.empty()) { System.out.println(stk.pop()); } } } |
(5)HashMap(“键-值映射对”的方法,此处使用学生的年龄作为键)
测试代码( HashMapDemo.java)如下所示:
import java.util.HashMap; import java.util.*; public class HashMapDemo { /** * @param args */ public static void main(String[] args) { HashMap<String,Student> hashmap=new HashMap(); hashmap.put("18", new Student(18,"张三"));//存放对象用put方法 hashmap.put("20", new Student(20,"王五")); hashmap.put("22", new Student(22,"李四")); System.out.println("HashMap:"+‘\n‘+hashmap); //该函数有其内部的排序方式,事实上是依据哈希算法来排序的。 Set set=hashmap.keySet();//获取全部键,返回类型是Set Iterator iterator=set.iterator(); while (iterator.hasNext()) { //System.out.println(iterator.next()+"="+hashmap.get(iterator.next())+";"); System.out.println(hashmap.get(iterator.next())+";"); } } } |
(6)TreeMap
TreeMap容器类比较特殊,TreeMap内部使用红黑树结构对“键”进行排序存放,所以放入TreeMap中的“键-值”对的“键”必须是可排序的。
测试代码(TreeMapTest.java)如下所示:
import java.util.Iterator; import java.util.Set; import java.util.TreeMap; public class TreeMapTest { public static void main(String[] args) { TreeMap treemap=new TreeMap(); treemap.put("18",new Student(18,"张三")); //指定键值,如果映射以前包含一个此键的映射关系,那么将替换原值 treemap.put("21",new Student(21,"王五")); treemap.put("19",new Student(19,"赵六")); System.out.println("\nTreeMap:\n"+treemap);//可以对键排序 System.out.println(treemap.firstKey());//返回第一个键 Set set=treemap.keySet(); Iterator iterator=set.iterator(); while (iterator.hasNext()) { System.out.println(treemap.get(iterator.next())+";"); } }} |
(7)Properties类(实现属性的读取和存放)
Properties类表示了一个持久的属性集,它可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串,它继承自HashTable,也即哈希表。Properties类存放的“键-值”对都是字符串。
测试代码(PropertiesTest.java)如下所示:
import java.io.IOException; import java.io.InputStream; import java.util.Properties; import javax.security.auth.login.Configuration; public class PropertiesTest { /** * @param args */ public static void main(String[] args) { //获取文件,并读入到输入流 InputStream is=Thread.currentThread().getContextClassLoader() .getResourceAsStream("Config.properties"); //创建属性级对象 Properties prop=new Properties(); try { //从流中加载数据 prop.load(is); } catch (IOException e) { e.printStackTrace(); } String name=prop.getProperty("name"); System.out.println("name="+name); String idString=prop.getProperty("id"); System.out.println("id="+idString); } } |
在此需要创建一个属性文件,命名为:config.properties,放于工程的src目录中。
属性文件内容如下:
#key=value
name=shenxiaolin\u6C88\u6653\u9E9F
id=105032013
4、请问java中有没有优先队列实现类,如果有,请编写程序,演示该类的使用。
优先级队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。PriorityQueue是从JDK1.5开始提供的新的数据结构接口。如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头,字符串则按字典序排列。
程序代码如下所示:
import java.util.Comparator; import java.util.PriorityQueue; import java.util.Queue; import java.util.function.Function; import java.util.function.ToDoubleFunction; import java.util.function.ToIntFunction; import java.util.function.ToLongFunction; public class PriorityQueueTest { public static class Student { // /** * @param args */ private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Student() { super(); // TODO Auto-generated constructor stub } public Student(int age, String name) { super(); this.age = age; this.name = name; } public String toString() { return "Student [age=" + age + ", name=" + name + "]"; } } public static void main(String[] args) { // TODO Auto-generated method stub Comparator<Student> OrderIsdn = new Comparator<Student>(){ public int compare(Student s1, Student s2) { // TODO Auto-generated method stub int age1 = s1.getAge(); int age2 = s2.getAge(); if(age2 > age1) { return 1; } else if(age2 < age1) { return -1;} else { return 0; } } }; PriorityQueue<Student> priorityQueue = new PriorityQueue<Student>(11,OrderIsdn); Student s1 = new Student(18,"张三"); Student s3 = new Student(19,"李四"); Student s2 = new Student(17,"王五"); priorityQueue.add(s1); priorityQueue.add(s3); priorityQueue.add(s2); while (!priorityQueue.isEmpty()) { System.out.println(priorityQueue.poll()); } } } |
五、实验总结
1.本次实验按时按量完成。
2.当有多个catch语句,在安排catch语句的顺序时,首先应该捕获子类异常,然后再捕获父类异常。如果顺序弄反了,后面捕获异常的代码将无法被调用。如果异常是同级关系,则无所谓哪个置前,哪个置后。
3.如果有需要使用return语句时,一个合理的做法是,既不在try内部使用return语句,也不在 finally内部使用 return语句,而应该在finally语句之后使用return 来表示函数的结束和返回。
4.一般都需要throw和throws语句的组合使用,就是在捕获异常后,抛出一个明确的异常给调用者。需要注意的是:throw语句是编写在方法之中的,而throws语句是用在方法签名之后的。在同一个方法中使用throw和throws时要注意,throws抛出的类型的异常范围要比throw抛出的对象范围大才可以。
5.Stack类继承自Vector,而Vector又有父类,这样Stack中出现了多余方法。若我们只希望Stack栈完成进栈和出栈功能就行,而不需要add等方法,则可通过LinkedList来完成,因为LinkedList链表结构可以快速地实现插入和删除操作。
6.因为PriorityQueueTest是一个动态的内部类,创建这样的对象必须有实例与之对应,程序是在静态方法中直接调用动态内部类会报错误。这样的错误好比类中的静态方法不能直接调用动态方法。可以把该内部类Student声明为static,或者不要在静态方法中调用。
7.此次实验主要是练习熟悉Java异常处理机制以及Java集合框架和泛型机制。通过编程代码的实践加深对这些知识的理解和巩固。