Is it acceptable practice in Java to nest try/catch statements?
I am trying to create an IP address in Android from a passed in value (using Bundle), and if it fails I'm creating it using a default IP address that is hard coded. If that fails then I am exiting the app.
What I'd like to know is if its ok to nest try/catch's as I have done here, or is there a better way.
try {
// serverSettings is the Bundle name that was passed in.
ipAddress = InetAddress.getByName(serverSettings.getString("serverIp"));
} catch (UnknownHostException e) {
Log.e("ERROR:", "IOException: Failed to create IP, trying default");
try {
// DEFAULT_IP is the hard-coded default fall-back address
ipAddress = InetAddress.getByName(DEFAULT_IP);
} catch (UnknownHostException e1) {
Log.e("ERROR:", "IOException: Total fail, exiting");
e1.printSta开发者_如何学运维ckTrace();
finish();
}
}
It's legal Java. It looks clunky to me, and I'd probably do it differently, but it's valid and works.
Here's how I'd do it:
public InetAddress getServerAddress() {
for (String address : new String[] {serverSettings.getString("serverIp"), DEFAULT_IP}) {
try {
return InetAddress.getByName(address);
} catch (UnknownHostException e) {
Log.e("ERROR:", "Cannot resolve " + address);
}
}
Log.e("ERROR:", "Total fail, exiting");
finish();
return null; // not reached
}
I think it's going to be debatable what way is better, but here's another option that some may consider to be a bit more "expressive" and readable, though it's more lines of code:
public InetAddress tryHost(String hostName) {
InetAddress address = null;
try {
address = InetAddress.getByName(hostName);
} catch (UnknownHostException e) {
e.printStackTrace();
}
return null;
}
Then in your code, just do:
InetAddress address = null;
address = tryHost(serverSettings.getString("serverIp"));
if (address = null)
address = tryHost(DEFAULT_IP);
if (address = null) {
// handle error, throw exception
}
finish();
Another variation is to set the default first:
ipAddress = null;
try {
// serverSettings is the Bundle name that was passed in.
ipAddress = InetAddress.getByName(DEFAULT_IP); // Set default address
ipAddress = InetAddress.getByName(serverSettings.getString("serverIp")); // Try passed-in address
} catch (UnknownHostException e) {
if (ipAddress == null) {
Log.e("ERROR:", "IOException: Total fail, exiting");
e1.printStackTrace();
finish();
}
}
If the call using the Bundle'd value fails, then the exception is thrown before ipAddress is modified, so ipAddress is already set to the default. Of course, this is only a valid pattern if DEFAULT_IP should always be resolvable.
It's OK. You could also use a boolean flag which gets turned on in the 1st catch, so you execute the request by IP outside the catch, if your boolean flag is turned on.
boolean failed = false;
try {
// serverSettings is the Bundle name that was passed in.
ipAddress = InetAddress.getByName(serverSettings.getString("serverIp"));
} catch (UnknownHostException e) {
failed = true;
Log.e("ERROR:", "IOException: Failed to create IP, trying default");
}
if(failed){
try {
// DEFAULT_IP is the hard-coded default fall-back address
ipAddress = InetAddress.getByName(DEFAULT_IP);
} catch (UnknownHostException e1) {
Log.e("ERROR:", "IOException: Total fail, exiting");
e1.printStackTrace();
finish();
}
}
}
I prefer this. It's a bit cleaner and doesn't involve extra flags.
InetAddress ipAddress = null;
try {
// serverSettings is the Bundle name that was passed in.
ipAddress = InetAddress.getByName(serverSettings.getString("serverIp"));
} catch (UnknownHostException e) {
Log.e("ERROR:", "IOException: Failed to create IP, trying default");
}
if(ipAddress==null){
try {
// DEFAULT_IP is the hard-coded default fall-back address
ipAddress = InetAddress.getByName(DEFAULT_IP);
} catch (UnknownHostException e1) {
Log.e("ERROR:", "IOException: Total fail, exiting");
e1.printStackTrace();
finish();
}
}
Yet another variation I like when working through a larger set of tests (on a first-wins basis):
ipAddress = null;
// serverSettings is the Bundle name that was passed in.
String[] addresses = { DEFAULT_IP,
serverSettings.getString("serverIp") };
int i = 0;
do {
try {
ipAddress = InetAddress.getByName(addresses[i]);
} catch (UnknownHostException e) {
Log.e("ERROR:", "IOException: Failed to create IP, trying next");
}
} while (ipAddress == null && i < addresses.length);
if (ipAddress == null) {
Log.e("ERROR:", "IOException: Total fail, exiting");
e1.printStackTrace();
finish();
}
This is probably more appropriate in my normal use case (looping through SimpleDateFormats to match 3rd-party date strings)
精彩评论