Always Check Type Before Cast

 class​ Network {
 
  ObjectInputStream inputStream;
  InterCom interCom;
 
 void​ listen() ​throws​ IOException, ClassNotFoundException {
 while​ (​true​) {
  Object signal = inputStream.readObject();
» CrewMessage crewMessage = (CrewMessage) signal;
  interCom.broadcast(crewMessage);
  }
  }
 }

Sometimes, you have to deal with dynamic object types at runtime. Dynamic objects can come from various sources, typically when serialized Java objects are exchanged through a channel. Before being able to use them in your program, you’ll need to explicitly cast them to a type. If you don’t do this properly, your program could crash with some kind of a RuntimeException.

In the code above, you can see a class that reads messages from an InputStream by calling its readObject() method. Such streams in Java are very flexible. For example, you can read input from a file or the network. But to make them so flexible, they aren’t typed and just provide you with a plain Object. It’s your responsibility to turn that into something your program can work with.

You do this with a cast to the type you expect. In the example above, that’s (CrewMessage). This will compile just fine and run smoothly as long as the objects in the stream are indeed of that type.

But the party is over when the stream returns a wrong type! The method has no control over which types are actually written into the stream. What if somebody on the other end of the stream inserts a different message type—for example, a ClassifiedMessage? Whatever the reason, you can be sure that at some point, there will be an object that’s not a CrewMessage. Then the method, and probably the complete program, will crash with a ClassCastException.

Can you catch this exception? You can, but you shouldn’t, as it typically indicates a bug in the code that you can fix. So instead you should repair the code.

Fortunately, all you have to do is a proper type check before the cast:

 class​ Network {
 
  ObjectInputStream inputStream;
  InterCom interCom;
 
 void​ listen() ​throws​ IOException, ClassNotFoundException {
 while​ (​true​) {
  Object signal = inputStream.readObject();
»if​ (signal ​instanceof​ CrewMessage) {
  CrewMessage crewMessage = (CrewMessage) signal;
  interCom.broadcast(crewMessage);
  }
  }
  }
 }

The code above first stores the result of reading from the stream in a local variable called signal. The variable’s type is Object, so this line can’t fail because of typing. After all, every non-primitive Java type inherits from Object.

Next, we make sure that we can read the signal by performing a type check using the instanceof operator. This operator returns true if signal can be cast to the type CrewMessage and false otherwise. We’re allowed to do the explicit cast only if the check was positive. It gives us certainty that a ClassCastException won’t happen here. We’re safe!

This requires additional lines of code, but there’s no other way to avoid a ClassCastException in Java. When you expect a set of different types—different types of messages in our example—you’ll have to do a sequence of checks with instanceof.

There’s another exception type in the method signature that you shouldn’t confuse with the ClassCastException. An ObjectInputStream triggers a ClassNotFoundException exception when it tries to read an object whose type isn’t in your program’s classpath. You can’t avoid that with a type check, obviously. Usually, this exception means that there’s something wrong in your execution setup, but it shouldn’t necessarily stem from a bug in your code. In production, you should also catch and log it. During development, it’s better to let the program crash and update the environment before continuing.

So keep in mind that whenever your program interacts with the outside (for example, using a stream), you need to make sure that it can handle unexpected input.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.74.160