开发者

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)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜