有风险的代码
import javax.sound.midi.*;
public class Test{
public void play(){
Sequencer sequencer = MidiSystem.getSequencer();
System.out.println("We got a sequencer");
}
public static void main(String[] args){
Test test = new Test();
test.play();
}
}
编译器提示,有异常未处理,因为getSequencer()
可能会在执行期间出问题。
try/catch
IDEA中使用快捷键,Alt+Enter,可以帮助纠正代码。
把有风险的代码放到try/catch
里,编译器会放心许多。
import javax.sound.midi.*;
public class Test{
public void play(){
try {
Sequencer sequencer = MidiSystem.getSequencer();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
System.out.println("We got a sequencer");
}
public static void main(String[] args){
Test test = new Test();
test.play();
}
}
- 声明有风险的方法时,使用
throws
抛出异常 - 调用有风险的方法时,方法放到
try
块里,异常处理程序放到catch
块里 - 编译器不检查运行时异常,大部分运行时异常是因为代码逻辑有问题
- 异常也是对象
try/catch/finally
finally
,无论如何都会执行的部分,即使try
或者catch
中有return
,也会finally
,最后才return
。
import javax.sound.midi.*;
public class Test{
public String play(){
try {
Sequencer sequencer = MidiSystem.getSequencer();
System.out.println("executing code in try");
return "executing return of try";
} catch (MidiUnavailableException e) {
e.printStackTrace();
System.out.println("executing code in catch");
}finally{
System.out.println("executing code in finally");
}
return "";
}
public static void main(String[] args){
Test test = new Test();
String res = test.play();
System.out.println(res);
}
}
多重异常
多重异常的声明
//ClothingException.java
public class ClothingException extends Exception {
}
//PantsException.java
public class PantsException extends ClothingException {
}
//ShirtException.java
public class ShirtException extends ClothingException {
}
一个方法可以抛出多个异常,逐个抛出,就像下面这样,
//Laundry.java
public class Laundry {
public void doLaundry() throws PantsException,ShirtException{
}
}
前面讲过,异常也是对象,因此可以使用多态。
如果两个或两个以上的异常有共同的父类,也可以只声明父类,就像这样,
//Laundry.java
public class Laundry {
public void doLaundry() throws ClothingException{
}
}
多重异常的处理
可以依次catch每个可能的异常。唯一要注意的是,有多个catch块时,要从小到大排列。
//Test.java
public class Test{
public static void main(String[] args){
Laundry laundry = new Laundry();
try {
laundry.doLaundry();
} catch (PantsException e) {
e.printStackTrace();
} catch (ShirtException e) {
e.printStackTrace();
}
}
}
也可以只catch它们的父类。
//Test.java
public class Test{
public static void main(String[] args){
Laundry laundry = new Laundry();
try {
laundry.doLaundry();
} catch (ClothingException e) {
e.printStackTrace();
}
}
}
声音播放程序
import javax.sound.midi.*;
//Test.java
public class Test{
public static void main(String[] args){
Test t = new Test();
t.play();
}
public void play(){
Sequencer player = null;
try {
//1.打开播放器
player = MidiSystem.getSequencer();
player.open();
//2.制作CD盘
Sequence seq = new Sequence(Sequence.PPQ,4);
//3.制作单曲,单曲烧至CD盘
Track track = seq.createTrack();
//4.给单曲添加音符
ShortMessage a = new ShortMessage();
a.setMessage(144,1,44,100);
MidiEvent noteOn = new MidiEvent(a,1);
track.add(noteOn);
ShortMessage b = new ShortMessage();
b.setMessage(128,1,44,100);
MidiEvent noteOff = new MidiEvent(b,16);
track.add(noteOff);
//5.CD盘插入播放器,播放盘中唯一单曲
player.setSequence(seq);
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
ShortMessage
ShortMessage实例描述了要做什么。setMessage(command,channel,data1,data2)
command
命令类型。
144代表开启;
128代表关闭;
192代表更换乐器。channel
代表频道 。data1
代表使用哪个音符,范围在0~127
之间。data2
代表音道。
0,代表几乎没有声音
100,音量还可以
MidiEvent
MidiEvent实例决定了什么时候做。new MidiEvent(message,tick)
tick
代表音长。
new MidiEvent(a,1)
,意思是在第一拍启动a
这个message。
现在我们把这两个步骤,8行代码通过一个静态方法来实现,如下,
public static MidiEvent makeEvent(int command,int channel,int data1,int data2,int tick){
MidiEvent event = null;
try {
ShortMessage message = new ShortMessage();
message.setMessage(command,channel,data1,data2);
event = new MidiEvent(message,tick);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
return event;
}
使用静态makeEvent
方法实现了一个新的声音播放器,运行试试看。
//Test.java
import javax.sound.midi.*;
public class Test{
public static void main(String[] args){
try {
Sequencer player = MidiSystem.getSequencer();
player.open();
Sequence sequence = new Sequence(Sequence.PPQ,4);
Track track = sequence.createTrack();
for(int i=5;i<61;i+=4){
track.add(makeEvent(144,1,i,100,i));
track.add(makeEvent(128,1,i,100,i+2));
}
player.setSequence(sequence);
player.start();
} catch(Exception e) {
e.printStackTrace();
}
}
public static MidiEvent makeEvent(int command,int channel,int data1,int data2,int tick){
MidiEvent event = null;
try {
ShortMessage message = new ShortMessage();
message.setMessage(command,channel,data1,data2);
event = new MidiEvent(message,tick);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
return event;
}
}