一、实验目的
掌握面向对象程序设计技术
二、实验环境
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)如下所示:
public class ThrowAndThrowsDemo {
/*** @param args*/
public static void main(String[] args) {
// TODO Auto-generated method stub
testThrow(args);
}
//调用有异常的方法
private static void testThrow(String[] tmp) {
// TODO Auto-generated method stub
try {
createThrow(tmp);
} catch (Exception e) {
System.out.println("捕捉来自createThrow方法的异常");
}
}
//抛出一个具体的异常
private static void createThrow(String[] tmp) throws Exception {
// TODO Auto-generated method stub
int number=0;
try {
number=Integer.parseInt(tmp[0]);
} catch (Exception e) {
// TODO: handle exception
throw new ArrayIndexOutOfBoundsException("数组越界");
}
System.out.println("你输入的数字为:"+number);
}
}
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集合框架和泛型机制。通过编程代码的实践加深对这些知识的理解和巩固。