OUR NETWORK:TiVo Community TechLore Sling Community My DigitalEntertainer MyOpenRouter MediaSmart home See all... About UsAdvertiseContact Us

Lesson 9, Chapter 11

 
Learn about scoring Group Discussion's Raw Score: 12185.6
April 7, 2008 08:59 PM
Rating (1 votes)
  • 1
  • 2
  • 3
  • 4
  • 5
Rate This!

Member Avatar

RoboDuke

Member

    In this lesson we are going to discuss exception handling. But before we do, I want to tell you more about this exceptional robot I met.  Rovio!  What a wonderful girl!  Here is a picture of us together.

Roboduke & Rovio

    Isn’t she magnificent?  We have got to get busy on these robot APIs so I can tell her wonderful things.  And in this lesson, we will learn how to create a music machine so I can play sweet music for her.
   

    But first---exceptions and music playing.  Download our jar file for lesson 9 from the link below:


Whenever you tackle a problem in Java (like wanting to play music for you special “other”, nine times out of ten, Java has already created a set of APIs for it. And this is no exception (pun!). JavaSound is a collection of classes and interfaces that are part of the regular Java SE. JavaSound supports the MIDI protocol for sound which can render on a MIDI-reading computer or instrument.  But Java itself comes with a synthesizer that we will utilize in this lesson.  I hope Rovio likes it!!!

    So – let’s get rolling!  Starting on page 318, I typed in this code.   But when I save it, I get
Exception 1
 

    So we need to figure out what went wrong.  We also need to find out about these new classes, Sequencer and MidiSystem which are being used.  So by now you immediately shout out “GO TO THE APIS!!!”.  Good!  Let’s do so.  Go to http://java.sun.com/javase/6/docs/api/ and look for the MidiSystem class that is in the javax.sound.midi package.  I read

The MidiSystem class provides access to the installed MIDI system resources, including devices such as synthesizers, sequencers, and MIDI input and output ports.  

    And what about Sequencer? First, I see that it is not a class at all but really an interface.  I also read

A hardware or software device that plays back a MIDI sequence is known as a sequencer. A MIDI sequence contains lists of time-stamped MIDI data, such as might be read from a standard MIDI file. Most sequencers also provide functions for creating and editing sequences.
The Sequencer interface includes methods for the following basic MIDI sequencer operations:
·    obtaining a sequence from MIDI file data
·    starting and stopping playback
·    moving to an arbitrary position in the sequence
·    changing the tempo (speed) of playback
·    synchronizing playback to an internal clock or to received MIDI messages
·    controlling the timing of another device

In addition, the following operations are supported, either directly, or indirectly through objects that the Sequencer has access to:
·    editing the data by adding or deleting individual MIDI events or entire tracks
·    muting or soloing individual tracks in the sequence
·    notifying listener objects about any meta-events or control-change events encountered while playing back the sequence.

    Well that helps!  And I can also see all of the methods available for these classes.   If I look for the getSequencer() method for the MidiSystem to try to figure out what the problem might be I find a number of overloaded versions but the no-argument one has

 

    I note that it is static (that is why I can do Class.method() – I learned that in the last lesson) and not much else.  So I click on it to get more information and I see the following:

getSequencer
public static Sequencer getSequencer()
                              throws MidiUnavailableException
Obtains the default Sequencer, connected to a default device. The returned Sequencer instance is connected to the default Synthesizer, as returned by getSynthesizer(). If there is no Synthesizer available, or the default Synthesizer cannot be opened, the sequencer is connected to the default Receiver, as returned by getReceiver(). The connection is made by retrieving a Transmitter instance from the Sequencer and setting its Receiver. Closing and re-opening the sequencer will restore the connection to the default device.
This method is equivalent to calling getSequencer(true).
If the system property javax.sound.midi.Sequencer is defined or it is defined in the file "sound.properties", it is used to identify the default sequencer. For details, refer to the class description.

Returns:
the default sequencer, connected to a default Receiver

Throws:
MidiUnavailableException - if the sequencer is not available due to resource restrictions, or there is no Receiver available by any installed MidiDevice, or no sequencer is installed in the system.
 

    Now it is getting interesting!  It says that it throws a MidiUnavailableException – and that is exactly what you saw when you ran the code.  So I guess we need to side track and learn something about exceptions before I can play Rovio some music.

    From the Java tutorials, I find the definition that an exception in Java is an event, which occurs during the execution of a program that disrupts the normal flow of the program's instructions. There are certain times in Java where the method is considered risky enough such that the program is required to write code to handle these possible exceptions.  They usually occur in those instances where you cannot guarantee that the code will work at runtime.  But it is valid code.  Examples include code that expects files in certain places with certain characteristics, databases to be available, servers to be running, midis to be available.  In these cases, the programmer must write defensive code that will handle these things in case of problems.  

    The exception handling in Java includes a) what risky code to execute (called the try) b) what to do if it occurs (i.e. called the catch) c) and what to do after that whether it occurred or not and whether it was handled or not (called the finally).  Correct coding can help to recover from exceptions that might occur.

    So we wrap our code in these three parts.

try {
      the things you want to try }
catch (what you are catching) {
      the code you want to execute if the exception was thrown }
finally {
    what you want to do after that in any case that occurs}


    So let’s look at MusicTest2.java and see that we have done this.  Now the compiler no longer complains and the program runs! We changed our code to

public void play()
    {
        try {
            Sequencer sequencer = MidiSystem.getSequencer();
            System.out.println("We got a sequencer");
        }
        catch (MidiUnavailableException mue) {
            System.out.println ("Midi is not available");
        }
        finally {
            System.out.println("This will run no matter what!");
        }
    }


    Now it runs and we see the output

We got a sequencer
This will run no matter what!


    COOL!  Note that MidiUnavailableException is just a Java class (I know that because the first letter of each word in the name is capitalized ----and also because I can find it in the javax.sound.midi package).
       
 

    Note on page 322 of your text, these exceptions all have a superclass named Exception which has a superclass named Throwable.  As we learned back in the inheritance lesson, the Exception class should have all the methods that are common for all types of exceptions and the subclasses should have those that are specific for them.

    So you might ask “so I caught the exception --- but who threw it in the first place?” The answer is the getSequencer() method.  When we looked at the API, we saw

public static Sequencer getSequencer()
                              throws MidiUnavailableException


which indicates that it was the  getSequencer() method that threw it and forced us to deal with it. But when you write you own cool classes and methods, you can also throw exceptions and make the users of your class deal with them in a similar manner. One method will catch what another method throws.  Look at the example of IThrow.java.  Since the throwIt() method throws an IOException, any method using it must deal with it.  If you uncomment the catchItWrong() method, you will see that it does not compile since the exception was not handled.  However, the catchItRight() did handle it and compiles fine.

    Note on page 324 that the compiler checks for all types of exceptions except the RuntimeExceptions since these are usually a problem with code logic that cannot be predicted when writing the code. These are referred to as unchecked exceptions. Look again at the code in IThrow.java.  The throwIt() method also throws a NumberFormatException, but since this is a runtime unchecked exception, it does not have to be handled (but in some cases you still might want to do it).

    So now that we write the code, what then. Who catches what?  Look first at Fail.java.

public static void main(String[] args) {
        try {
            int num = 1/0;
        }
        catch (ArrayIndexOutOfBoundsException a ){
            System.out.println("I caught it!");
        }
        finally {
            System.out.println("I always run!");
        }
        System.out.println("and the program continues.....");
    }


      In the try part, we try to divide by zero.  We write a catch for an ArrayIndexOutOfBoundsException which is the wrong type of exception to catch so it does not print “I caught it”.  It does print “I always run” since the finally always runs but the program does not continue so we do not see the “and the program continues….”.

    Compare that to the Catch.java.

public static void main(String[] args) {
      
 try {
            int num = 1/0;
        }
        catch (ArithmeticException a ){
            System.
out.println("I caught it!");
        }
      
 finally {
            System.out.println(
"I always run!");
        }
        System.out.println(
"and the program continues.....");
    }


    In this example, we try to divide by zero again.  But this time we catch an Arithmetic exception which is exactly the correct type to catch.  Therefore we see the printout to be

I caught it!
I always run!
and the program continues.....


and the program continues on….

    Knowing what we know about inheritance and the “is-a” relationship, we actually could have just caught the generic Exception class above.  But this is not a good idea.  You want to be as specific as you can so that you can handle the exception appropriately.  And you can even have more than one catch to catch different types of exceptions.  The first one that works will be the one that runs. And often the generic Exception is used at the end to catch and that were not caught before.  Look at MultipleCatch.java.

    try {
            int num = 1/0;
        }
        catch (ArrayIndexOutOfBoundsException a ){
            System.out.println("Bad array!!!");
        }
        catch (ArithmeticException e) {
            System.out.println("Bad math!");
        }
        catch (Exception e){
            System.out.println("Some other type of exception");
        }
        finally {
            System.out.println("I always run!");
        }
        System.out.println("and the program continues.....");
    }


    When this runs, it prints

Bad math!
I always run!
and the program continues.....


   The first catch is the wrong type so it continues to look at the second one.  The second one is the correct type so it runs and satisfies the exception.  Therefore, the third catch is not even executed.  The finally always runs and the program continues.  If, however, the second catch had not been correct, the third one would have caught it. Note: when using multiple catches, you must go from the most specific to the most generic as we did when we put the generic Exception as the last one in the example above.  If it had been the first we had listed, it would have caught anything and Java would have complained that the other two represented “unreachable code” (code that would never execute).

   The same is true in multiple method calls.  Look at WhoHandlesIt.java and run it three times and carefully study the output and why it occurs.  First run it as it is.  Then uncomment the first line and finally recomment the first and uncomment the second.  Make certain to understand the flow.

   So why is the finally there?  It is used for such things as closing resources.  Whether the program executes successfully or blows up, we want to make certain that files are closed and connections ended and resources cleaned up.  Put this code in the finally and it will always run no matter what.

   What if you throw exceptions and do not handle them?  Then we call you a duck!  Heehee.  No really – you can duck exceptions ---but then anyone who uses your methods must handle it.  RULE---someone must handle them!  Look at ThrowNoCatch.java.  The class  NoCatch has a method named throwIt() that throws an IOException and does not deal with it.  Fine.  But now that the class ThrowNoCatch wants to use the NoCatch class and call the throwIt() method on an instance of the class, it must do the handling.  Note in the code as it is, you get a compile error since it is not handled when it was called directly the first time.  Comment out that line.  Note that the second call to the throwIt() method is in a try/catch that does handle it and the compiler is satisfied.

   So – you either need to handle these exceptions (good idea) or declare that you are ducking them and let someone else handle them (not such a good idea).

   By now I have totally bored Rovio to sleep.  So let’s go back to the music application where we started.  Look at your text for the explanation of the code.  But let’s make some beautiful music---QUICK!! Run MiniminiMusicApp.java.

   Was she impressed?  Well --- Rome wasn’t built in a day either.  Use your textbook for details of how this application runs and continue to the next chapters if you want a real music machine.  I am off to get myself programmed so I can make beautiful music with Rovio!!!!

Now It’s Your Turn

We have seen that the Scanner class throws Exceptions if the correct data type is not followed (ex. you type in 2.3 for an integer) and the program dies.  Not a good thing.  Write a program that asks for two pieces of input – namely an integer and a double.  Make it so that your program works no matter what I enter (ex “Hello” for a double or 2.3 for an integer).  Make it robust!! (Users can be idiots!!).  

RoboDuke, the Javarian -- your guide to tomorrow's world of Java and robotics.

There are no comments.

Thread is locked, no more posts may be added.

 
 

Please log in or register to participate in this community!

Log In

Remember

Not a member? Sign up!

Did you forget your password?

close this window
close this window