Person p = new Person("Person number " + i, (age - 50));What happens when you run the program now?
You get a load of -ve ages in the list of created Persons
Your constructor will now look like this:
public Person(String name, int age, Color hair) { if (age < 0) { throw new IllegalArgumentException("age too small"); } this.name = name; . . .What do you expect will happen when you try to compile the program now?
You might expect the compiler to complain about a missing "throw" clause on
the constructor. It doesn't though, because
IllegalArgumentException
is a subclass of
RuntimeException
, and RuntimeException
s don't have
to be caught. Note that you could have a "throws" clause if you want, but you
aren't required to.
Your main loop will now look something like this:
for (int i=0; i<20; i++) { // Create a new person with random age int age = (int) (Math.random() * 70); try { Person p = new Person("Person number " + i, (age - 50)); myCollection.add(p); } catch (IllegalArgumentException e) { System.out.println("Couldn't add person with age of " + (age - 50)); } }By limiting the scope of the try..catch block to a single iteration, you'll still get the +ve aged Persons in the list.
You'd expect the compiler to complain about uncaught
Exception
s.
You'll need to change all the constructor definitions so that they say
throws Exception
and you'll have to change your
try..catch
block to catch Exception
.
Here's a minimal example (javadoc missing):
public class SillyAgeException extends Exception { public SillyAgeException() {} }
Change your Person class so that it throws a SillyAgeException for minus ages
Doing this means you'll should :
if (age < 0) { throw new SillyAgeException(); }
SillyException
. Note you don't have to do this here but it would
be good practise - when using exceptions you should be as precise as possible.
try..catch
clause to catch
SillyException
Here's one way to do this:
public class SillyAgeException extends Exception { int requestedAge; /** * The only constructor for this class, which requires that you * say what the silly age was */ public SillyAgeException(int sillyAge) { requestedAge = sillyAge; } /** * Return the age that was invalid */ public int getRequestedAge() { return requestedAge; } /** * Returns a message containing the silly age */ public String getMessage() { return "Age of " + requestedAge + " is silly!"; } }In the Person code, catch any SillyAgeExceptions, and display a message reporting what the silly age was.
Now you'll have to make sure that Person is catching
SillyAgeException
and not Exception
everywhere, then
your main loop will look like this:
for (int i=0; i<20; i++) { // Create a new person with random age int age = (int) (Math.random() * 70); try { Person p = new Person("Person number " + i, (age - 50)); myCollection.add(p); } catch (SillyAgeException e) { System.out.println("Couldn't add person with age of " + e.getRequestedAge()); } }
The "compareTo" method will now look like this:
public int compareTo(Object o) { if (o instanceof Person) { Person other = (Person)o; if (other.age > age) { return 1; } if (other.age < age) { return -1; } } // The object wasn't a Person, or it was // a Person with the same age throw new ClassCastException("Not a person!"); // Don't need a return statement here because we'll // never get this far }
Your main method will now look like this:
public static void main(String [] args) { try { java.util.LinkedList myCollection = new java.util.LinkedList(); for (int i=0; i<20; i++) { // Create a new person with random age int age = (int) (Math.random() * 70); try { Person p = new Person("Person number " + i, (age - 50)); myCollection.add(p); } catch (SillyAgeException e) { System.out.println("Couldn't add person with age of " + e.getRequestedAge()); } } java.util.Iterator it = myCollection.iterator(); while (it.hasNext()) { Object o = it.next(); System.out.println(o); } System.out.println("The collection has " + myCollection.size() + " elements"); } finally { System.out.println("The program is now finishing"); } }
$ java Person 25
The "25" will be passed in as the first element of the "args" array. But
since that is an array of Strings, you need to turn it into an integer, which
you can do using a static method in the Integer
class:
int numObjects = Integer.parseInt(args[0]);
You could do this:
int numObjects = Integer.parseInt(args[0]); if ((numObjects < 5) || (numObjects > 100)) { throw new IllegalArgumentException("choose between 5 and 100"); }
The very last thing before the command prompt
Depending on what kind of exception you're throwing:
RuntimeException
(as is the case in
the sample above, where IllegalArgumentException
is used),
then the compiler won't make you have a "catch" clause. In this case, the
exception will be propagated to the JVM after the program has exited. So
you'll see the "finishing" message as your program terminates, followed by
the exception message which the JVM will display when control passes back
to it with the uncaught exception.RunTimeException
, (e.g. if you just throw
Exception
), then you will be forced by the compiler to
provide a catch
clause (or have throws Exception
on the declaration for main()
). If you catch the exception
yourself, then the "finishing" will be displayed after your catch block.
If you don't catch it (i.e. let it be thrown to the JVM), then the
"finishing" will be displayed before any exception message).