I read many posts on SO about java exception handling but I did get satisfy answer yet.Why should I put them in my codes ?
Java exception handlings make separating error handling codes from my business logic
Where is separating error handling in below snippet ?
public int division(int divident, int divisor) {
int result = 0;
try {
result = divident / divisor;
} catch (ArithmeticException e) {
System.out.println("Divisor must not be zero !");
}
return result;
}
3. Java's default exception handling makes showing exception information in standard output and terminate the program. Am I use exception handling by myself to avoid terminating from my programs?
It's three questions, but it's not like that's the first time that's happened here. :-)
Yes, you must handle them or declare them, because they're checked exceptions. The reason you must do that is so that the code calling your code knows the ways in which your code may fail (because you've declared the exceptions it can throw).
That snippet is very simple, so the separation and benefit aren't all that clear. But consider opening two streams, copying from one to another, with transformation code (including calls to subordinate methods). You end up with a method body with 10-20 statements in it. Instead of every I/O statement having to check whether it worked or not, you just write your logic wrapped in an IOException
handler, knowing that any I/O exceptions will jump out of the main logic into the handler.
It depends on what kind of program you're writing, but in general you handle exceptions at the most appropriate level, which is typically at multiple levels in your program. The outermost level, which is only to deal with really, really unusual, unrecoverable exceptions, would either just let the default handling do what it does, or use a catch-all handler that does something similar but might (attempt to) record the failure elsewhere (like a log file) as well:
public class MyProgram { public static final void main(String[] args) { try { // Run... } catch (Throwable t) { // Handle the fact that something went wrong here, if you can // Usually this would be only for really, really unusual errors, // otherwise you would have handled them earlier } } }
To underscore the point in #2, consider two process
methods, one in Java with exceptions, and the other in a hypothetical Java-like language that doesn't have exceptions:
The Java one:
private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}
The hypothetical Java-like language without exceptions one:
// THIS IS FAKE, PSEUDO-JAVA
private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}
bw.close();
br.close();
return Errors.Success;
}
Notice:
process
, and then we check for null
from new FileReader
and such, and check for -1 from read and write ops, etc. If you're interested, here's a full version of the Java program vs. the full version of the not-really-Java program:
Java:
import java.io.*;
public class Example
{
private String sourceFileName;
private String destFileName;
public static void main (String[] args) throws java.lang.Exception
{
try {
new Example(args[0], args[1]).process();
}
catch (ArrayIndexOutOfBoundsException npe) {
// This is a bit of an exaggeration, I'd check in advance, since the user not
// supplying arguments isn't really an "exceptional" condition.
System.out.println("Usage: java Example [source file name] [dest file name]");
}
}
public Example(String src, String dest) {
// Similar, these checks would probably be assertions, but I'm making a point...
if (src == null || src.length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (dest == null || dest.length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
this.sourceFileName = src;
this.destFileName = dest;
}
private void process() {
try ( // <== Main logic
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
) { // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != null) { // <== Main logic
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
bw.write(line); // <== Main logic
bw.newLine(); // <== Main logic
} // <== Main logic
} // <== Main logic
}
catch (FileNotFoundException fnfe) { // <== Error handling
// Couldn't find a file // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (IOException ioe) { // <== Error handling
// I/O error // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
catch (Exception e) { // <== Error handling
// Something else went wrong // <== Error handling
// (handle it) // <== Error handling
} // <== Error handling
}
private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}
private String transformLine(String line) {
return line.toUpperCase();
}
}
The hypothetical Java-like language without exceptions one:
// THIS IS FAKE, PSEUDO-JAVA WITHOUT EXCEPTIONS, IT ISN'T REAL
import java.io.*;
public class Example
{
private String sourceFileName;
private String destFileName;
private enum Errors {
Success,
CantOpenSource,
CantOpenDest,
CantRead,
CantWrite
}
public static void main (String[] args) throws java.lang.Exception
{
if (args.length < 2) {
System.out.println("Usage: java Example [source file name] [dest file name]");
}
if (args[0] == null || args[0].length() == 0) {
throw new IllegalArgumentException("src must be non-null and non-blank");
}
if (args[1] == null || args[1].length() == 0) {
throw new IllegalArgumentException("dest must be non-null and non-blank");
}
switch (new Example(args[0], args[1]).process()) {
case Errors.CantOpenSource:
// Handle it
break;
case Errors.CantOpenDest:
// Handle it
break;
case Errors.CantRead:
// Handle it
break;
case Errors.CantWrite:
// Handle it
break;
}
}
public Example(String src, String dest) {
// Not how now this constructor is trusting that it is called with valid arguments
this.sourceFileName = src;
this.destFileName = dest;
}
private Errors process() {
Reader fr = new FileReader(this.sourceFileName); // <== Main logic
if (fr == null) { // <== Error handling
return Errors.CantOpenSource; // <== Error handling
} // <== Error handling
BufferedReader br = new BufferedReader(fr); // <== Main logic
Writer fw = new FileWriter(this.destFileName); // <== Main logic
if (fw == null) { // <== Error handling
br.close(); // <== Error handling
return Errors.CantOpenDest; // <== Error handling
} // <== Error handling
BufferedWriter bw = new BufferedWriter(fw) // <== Main logic
String line; // <== Main logic
while ((line = br.readLine()) != IO.END_OF_FILE) { // <== Main logic
if (line == null) { // <== Error handling
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantRead; // <== Error handling
}
if (shouldIncludeLine(line)) { // <== Main logic
line = transformLine(line); // <== Main logic
if (bw.write(line) == -1 || bw.newLine() == -1) { // <== Main logic (plus some error handling)
br.close(); // <== Error handling
bw.close(); // <== Error handling
return Errors.CantWrite; // <== Error handling
}
}
}
bw.close();
br.close();
return Errors.Success;
}
private boolean shouldIncludeLine(String line) {
return line.length() != 0;
}
private String transformLine(String line) {
return line.toUpperCase();
}
}
1) If it's unreasonable for your code to be able to handle an exception, you can catch the checked exceptions thrown from your API calls and wrap them in an unchecked exception. Make sure you save the original checked exception as a cause in the new unchecked exception.
2) Your example snippet is not separating error-handling from business logic, it's glomming them together and obfuscating the result. There are two benefits of throwing the arithmetic exception here rather than passing back a default value: a) it's too difficult to distinguish a value passed to flag an error from a value that is the result of a valid computation and b) further business logic steps may depend on having calculated a valid value here, in which case you will have to leave the current flow anyway, you might as well use the exception for that.
3) It depends on the application. For a simple console program sometimes the best thing to do is let the error terminate the program. For a web application exceptions usually bubble up to a global exception handler, terminating that request but letting other requests proceed. For unit tests an exception is caught by the test runner and logged so that other tests can proceed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.