第十一章 异常处理

创建MIDI音乐播放器
1.首先我们需要一个Sequencer
   
   
package MidiPlayer;
import javax.sound.midi.*;
 
public class MusicTest1 {
public void play() {
//这个对象的作用是将Midi信息组合成乐曲;
Sequencer sequencer = MidiSystem.getSequencer();
System.out.println("We got a sequencer");
}//关闭播放
public static void main(String[] args) {
MusicTest1 mt = new MusicTest1();
mt.play();
}
}
进行编译时发现出错,错误 Exception in thread "main" java.lang.Error: Unresolved compilation problem:      Unhandled exception type  MidiUnavailableException
表示有异常情况必须要处理。

Java的异常处理(exception-handling)机制是个简捷轻量化的执行运行期间例外状况处理方式,让你知道所调用的方法是有风险的,就可以预先对其进行处理。
查找API时,如果提示throws就可以了解该方法可能抛出的异常


getSequencer()这个方法可能会在执行期间出问题,所以必须声明调用它时可能出现的风险

try/catch块会告诉编译器你确实知道所调用的方法有风险,并且也已经准备好处理它,它只会注意你有没有表示你会注意到异常。
因此对以上程序做一下修改:
   
   
package MidiPlayer;
import javax.sound.midi.*;
 
public class MusicTest1 {
public void play() {
//这个对象的作用是将Midi信息组合成乐曲;
try{
Sequencer sequencer = MidiSystem.getSequencer();
System.out.println("We got a sequencer");//把有风险的块放在try块
}catch(MidiUnavailableException ex){
System.out.println("Bummer");//用catch块摆放异常状况的处理程序
ex.printStackTrace(); //如果无法从异常中恢复至少也要使用PrintStackTrace()来列出有用的信息
}
}//关闭播放
public static void main(String[] args) {
MusicTest1 mt = new MusicTest1();
mt.play();
}
}


异常是一种Exception类型的对象,它是对象,所以我们catch住的也是对象,线面代码中catch的参数是Exception类型的ex引用变量
   
   
try{
//危险动作
} catch(Exception ex) {
//尝试恢复
}
在编写可能会抛出异常的方法时,他们都必须声明有异常
有风险会抛出异常的程序代码
   
   
public void takeRisk() throws BadException { //必须声明他会抛出BadException
if(abandonAllHope) {
throw new BadException();//创建Exception对象并抛出
}
}


异常类型



编译器会核对除了RunTimeException以外的异常,RunTimeException成为不检查异常,编译器保证:
1如果你有抛出异常,则你一定要用throw来声明这件事
2.如果你调用会抛出异常的方法,你必须得确认你知道异常的可能性,将调用包在try/catch快中是一种满足编译器的方法


finally:无论如何都要执行的部分
   
   
try {
turnOvenOn();
x.bake;
} catch (BakingException ex) {
ex.printStackTrace();
} finally {
turnOvenOff();
}
无论try是否成功,都会跳到finally继续执行
注意如果try或catch快中有return指令,会先跳到finally中执行然后再回到return中执行。

如果有必要的话程序可以抛出多个异常。
编译器会检查你是否处理所有可能的异常,将个别的catch块逐个放在try块下。
    
    
public class Laundry() {
public void doLaundry() throws PantsException, LingerieException {
//有可能抛出两个异常的程序代码
}
}
     
     
public class Foo {
public void go() {
Laundary laundary = new Laundary();
try {
laundary.doLaundary()
} catch (PantsException pex) {
//恢复程序代码
} catch (LingerieException lex) {
//恢复程序代码
}
}
}
异常也是多态的。
1.以异常的父型来声明会抛出的异常
    
    
public void doLaundry() throws ClothingException {
//声明成ClothingException可让你抛出任何他的自类

2.以所抛出的异常父型来catch异常
    
    
try {
laundry.doLaundry();
} catch (ClothingException ex) {
//可以catch任何ClothingException的自类
}

可以把异常处理程序代码写成只有一个catch块以父型Exception来捕获,可以抓到任何可能被抛出的异常,但你会搞不定这是哪里出错。
为每个需要单独处理的异常编写不同的catch块。
有多个catch块时要注意从小排到大

不想处理异常时,可以把它duck掉来避开。
    
    
void foo() throws ClothingExceotion {
laundry.doLaundry();
}
//有声明会抛出异常,去没有try/catch块,所以就会duck掉异常给调用方
这意味着foo()的程序的调用方必须要处理或者也跟着声明异常


异常处理规则:
1.catch和finally不能没有try
2.try与catch之间不能有程序
3.try一定要有catch或者finally
4.只带有finally的try必须要声明异常
    
    
void go() throws FooException {
try {
x.doStuff();
} finally {}
}

回到midi音乐播放程序
4项必备的条件


史上第一个声音播放程序
    
    
package MidiPlayer;
import javax.sound.midi.*;
 
public class MiniMiniMusicApp {
public static void main(String[] args) {
MiniMiniMusicApp mini = new MiniMiniMusicApp ();
mini.play();
}//关闭main
void play() {
try {
Sequencer player = MidiSystem.getSequencer();
player.open(); //取得Sequencer并将其
Sequence seq = new Sequence(Sequence.PPQ, 4);
//先不看参数的意义
Track track = seq.createTrack();
//要求取得track
ShortMessage a = new ShortMessage();
a.setMessage(144, 1, 44, 100);//代表发送44音符 类型,频道,音符,音道
//144表示打开,128表示关闭, 频道代表不同的演奏者,例如1号是吉他,2号是贝斯 音符:0~127表示不用音高 音道:用多大的音道按下,0表示听不到,100算是差不多
MidiEvent noteOn = new MidiEvent(a, 1);//第一拍启动a这个Message
track.add(noteOn);//Track带有全部的MidiEvent对象,Sequence会根据事件事件组织它们,然后Sequencer会根据此顺序来播放,同一时间可以执行多个操作
ShortMessage b = new ShortMessage();
b.setMessage(128, 1, 44, 100);
MidiEvent noteOff = new MidiEvent(b, 16);
track.add(noteOff);
//对Track加入几个MidiEvent,要注意的是setMessage()的参数,以及MidiEvent的constructor
player.setSequence(seq);//将Sequence送到Sequencer上
player.start();//开始播放
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
第二版:使用命令列参数
这个版本还是播放单一的音符而已,但你可以使用命令列参数来改变乐器和音符,试试看传入两个介于0~127的整数参数,第一个参数设定乐器,第二个整数设定音符
    
    
package MidiPlayer;
import javax.sound.midi.*;
 
 
public class MiniMusicCmdLine {
 
public static void main(String[] args ) {
MiniMusicCmdLine mini = new MiniMusicCmdLine();
if (args.length < 2) {
System.out.println("Don't forget the instrument and note args");
} else {
int instrument = Integer.parseInt(args[0]);
int note = Integer.parseInt(args[1]);
mini.play(instrument, note);
}
}//关闭main
public void play(int instrument, int note) {
try {
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence seq = new Sequence(Sequence.PPQ, 4);
Track track = seq.createTrack();
MidiEvent event = null;
ShortMessage first = new ShortMessage();
first.setMessage(192, 1, instrument, 0);
MidiEvent changeInstrument = new MidiEvent(first, 1);
track.add(changeInstrument);
ShortMessage a = new ShortMessage();
first.setMessage(144, 1, note, 100);
MidiEvent noteOn = new MidiEvent(a, 1);
track.add(noteOn);
ShortMessage b = new ShortMessage();
first.setMessage(128, 1, note, 100);
MidiEvent noteOff = new MidiEvent(b, 16);
track.add(noteOff);
player.setSequence(seq);
player.start();
 
} catch (Exception ex) {ex.printStackTrace();}
}//关闭播放
}//关闭类



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值