I'm learning about Java and exception handling and the try/catch blocks. And I'm doing an example from YouTube, and I want to ask you if this is a pattern or something when you use 2 try blocks and one catch block:
private List<User> parseCSVFile(final MultipartFile file) throws Exception {
final List<User> users = new ArrayList<>();
try {
try (final BufferedReader br = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
final String[] data = line.split(",");
final User user = new User();
user.setName(data[0]);
user.setEmail(data[1]);
user.setGender(data[2]);
users.add(user);
}
return users;
}
} catch (final IOException e) {
logger.error("Failed to parse CSV file {}", e);
throw new Exception("Failed to parse CSV file {}", e);
}
}
I try to understand why this approach is better than using a try and a catch block like this:
try (final BufferedReader br = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
final String[] data = line.split(",");
final User user = new User();
user.setName(data[0]);
user.setEmail(data[1]);
user.setGender(data[2]);
users.add(user);
}
return users;
} catch (final IOException e) {
logger.error("Failed to parse CSV file {}", e);
throw new Exception("Failed to parse CSV file {}", e);
}
Two nested try-blocks in the first code snippet are redundant. When an exception occurs, it would be propagated until the point where it can be handled (or otherwise the execution would terminate).
Regarding the usage of try-blocks, you need to understand that it doesn't make sense having try without catch or finally (and compiler will not allow that).
Note that in case of try-with-resources try(myResource){}, you do have an implicit finally-block, therefore even without a catch-block try-with-resources can be useful and perfectly valid from the compiler perspective of view.
For more information on exception-handling refer to the official tutorial provided by Oracle.
EDIT
Looks like java changed behavior of try-with-resource, so my answer is no longer valid.
It did explains why you can see double try in some old tutorials.
ORIGINAL POST
Try with resources is syntactic sugar.
try(A a = foo()){
bar();
} catch (E e) {
}
is equivalent of
A a = foo();
try {
bar();
} catch (E e) {
} finally {
a.close();
}
Which mean exception thrown from foo won't be caught. therefore you need another try ... catch.
Related
I don't want toJson to throw an Exception, but the finally block might throw it.
Would it be preferable to wrap the bas.close() in a try/catch block or should this be re-written using try-with-resources
public String toJson() {
String json = null;
ByteArrayOutputStream bas = null;
try {
bas = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(bas, this);
json = new String(bas.toByteArray());
} catch (Exception e) {
log.trace("Unable to parse JSON", e);
} finally {
if (bas != null) {
bas.close();
}
}
return json;
}
You should do it using the try-with-resources statement. Given below is an excerpt from the Oracle's tutorial on The try-with-resources Statement which clearly states the benefit of using it:
Prior to Java SE 7, you can use a finally block to ensure that a
resource is closed regardless of whether the try statement completes
normally or abruptly. The following example uses a finally block
instead of a try-with-resources statement:
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
However, in this example, if the methods readLine and close both throw
exceptions, then the method readFirstLineFromFileWithFinallyBlock
throws the exception thrown from the finally block; the exception
thrown from the try block is suppressed. In contrast, in the example
readFirstLineFromFile, if exceptions are thrown from both the try
block and the try-with-resources statement, then the method
readFirstLineFromFile throws the exception thrown from the try block;
the exception thrown from the try-with-resources block is suppressed.
In Java SE 7 and later, you can retrieve suppressed exceptions; see
the section Suppressed Exceptions for more information.
Using the try-with-resources statement, you can write your method as follows:
public String toJson() throws Exception {
String json = null;
try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(bas, this);
json = new String(bas.toByteArray());
}
return json;
}
I'd proabably go with something along the lines of:
public String toJson() {
try (var bas = new ByteArrayOutputStream()) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(bas, this);
return new String(bas.toByteArray());
}
catch (Exception ie) {
throw new MyCustomJsonConverterException("Failed to render to JSON");
}
}
i.e. map to a RuntimeException type if you expect failure to serialize to JSON to be exceptional (a programming error). This is an instance method, after all, and all invariants of the class should already be enforced elsewhere. This way, you take the burden of checking for null from the caller.
What is the best handle a csv Spring Multipartfile?
I have used something like this before:
public void handleFile(MultipartFile multipartFile){
try{
InputStream inputStream = multipartFile.getInputStream();
IOUtils.readLines(inputStream, StandardCharsets.UTF_8)
.stream()
.forEach(this::handleLine);
} catch (IOException e) {
// handle exception
}
}
private void handleLine(String s) {
// do stuff per line
}
As far as I know, this first loads the whole file into a list in memory before processing it, which will probably take quite some time for files with tens of thousends of lines.
Is there a way to handle it line by line without the overhead of implementing the iteration by hand (i.e. using stuff like read(), hasNext(), ...)?
I am looking for something concise similar to this example for files from the file system:
try (Stream<String> stream = Files.lines(Paths.get("file.csv"))) {
stream.forEach(this::handleLine);
} catch (IOException e) {
// handle exception
}
In cases when you have InputStream you can use this one:
InputStream inputStream = multipartFile.getInputStream();
new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))
.lines()
.forEach(this::handleLine);
In other cases:
No matter whether it is multipart file or you have multiple independent files, there are many approaches to do it in Java 8 using Stream API:
Solution 1:
If your files are in different directories you can do it this way:
Imagine you have a List of String which contains paths of your files like below:
List<String> files = Arrays.asList(
"/test/test.txt",
"/test2/test2.txt");
Then you can read all lines of above files as below:
files.stream().map(Paths::get)
.flatMap(path -> {
try {
return Files.lines(path);
} catch (IOException e) {
e.printStackTrace();
}
return Stream.empty();
}).forEach(System.out::println);
Solution 2:
You can also read all lines of files that exist in /test/ehsan directory using Files.walk in the following way:
try (Stream<Path> stream = Files.walk(Paths.get("/test/ehsan"), 1)) {
stream.filter(Files::isRegularFile)
.flatMap(path -> {
try {
return Files.lines(path);
} catch (IOException e) {
e.printStackTrace();
}
return Stream.empty();
})
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
And if you want to read all lines of files in /test/ehsan directory recursively you can do it this way:
try (Stream<Path> stream = Files.walk(Paths.get("/test/ehsan"))) {
stream.filter(Files::isRegularFile)
.flatMap(path -> {
try {
return Files.lines(path);
} catch (IOException e) {
e.printStackTrace();
}
return Stream.empty();
})
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
As you can see the second parameter to Files.walk specifies the maximum number of directory levels to visit and if you don't pass it the default will be used which is Integer.MAX_VALUE.
Solution 3:
Lets not stop here, we can go further. what if we wanted to read all lines of files exist in two completely different directories for example /test/ehsan and /test2/ehsan1?
We can do it but we should be cautious, Stream should not be so long( because it reduces readability of our program) it will be better to break them in separate methods, However because it is not possible to write multiple methods here I will write in one place how to do that:
Imagine you have a List of String which contains paths of your directories like below
list<String> dirs = Arrays.asList(
"/test/ehsan",
"/test2/ehsan1");
Then we can do that this way:
dirs.stream()
.map(Paths::get)
.flatMap(path -> {
try {
return Files.walk(path);
} catch (IOException e) {
e.printStackTrace();
}
return Stream.empty();
})
.filter(Files::isRegularFile)
.flatMap(path -> {
try {
return Files.lines(path);
} catch (IOException e) {
e.printStackTrace();
}
return Stream.empty();
})
.forEach(System.out::println);
public static List<String> readCSV(String fileName) throws IOException {
List<String> records = new ArrayList<>();
try (BufferedReader br = new BufferedReader(
new FileReader(fileName))) {
String line;
while ((line = br.readLine()) != null) {
records.add(line);
}
}
return records;
}
I am using this link as a reference for creating custom exceptions. For my class practice, if no file is selected or passed in, my custom UnknownFileException should occur, but when I go and run my driver and put in an invalid filename I get a nullpointerexception instead?
My driver which has Adventure adventure = new Adventure(args[0]).
My custom exception:
import java.io.FileNotFoundException;
public class UnknownFileException extends FileNotFoundException {
public UnknownFileException() {
super("We couldn't tell what file this is");
}
public UnknownFileException(String message) {
super(message);
}
}
Code:
public class practice {
public String[] array;
public String line;
public PrintWriter outputStream = null;
public Scanner inputStream = null;
public practice(String fileName) throws UnknownFileException {
array = new String[100];
try {
inputStream = new Scanner(new FileReader(fileName));
line = inputStream.nextLine();
array[0] = line;
for (int i = 1; i < array.length; i++) {
array[i] = inputStream.nextLine();
}
outputStream = new PrintWriter(new
FileOutputStream("newFile.txt"));
} catch(UnknownFileException e) {
System.out.println(e.getMessage());
} catch (FileNotFoundException e) {
throw new UnknownFileException(e.getMessage());
} finally {
inputStream.close();
}
}
}
You probably got a stack trace, which should have pointed you to the line throwing the NullPointerException. I'm guessing it was this line:
inputStream.close();
The problem is that if you put in an invalid file name, new Scanner(new FileReader(fileName)) will throw, and inputStream will never be assigned. Because you have a finally block, however, before it throws your custom exception, it will try to execute the finally. But this gives a NullPointerException because inputStream is null, and that exception takes precedence, I believe (I'd have to check the language rules to make sure of what happens in this case).
Fix your finally block to test whether inputStream is null.
More: It's ยง14.20.2 of the JLS. This is pretty complicated, but basically if any exception is thrown from the finally block, any earlier exception thrown or caught is discarded.
inputstream is still null
Make the following change:
} finally {
if (inputStream != null) {
inputStream.close();
}
}
or use try-with-resources instead.
I'm trying to write a test case for the method setTrailer() within the class ErParser. setTrailer() has try-catch clauses, and in one of its catch clauses, it catches NullPointerException. I'm trying to write a Junit test for the case where setTrailer() throws and catches a NullPointerException, but the test case keeps failing. Is it because I already caught the exception in the method itself? Should I be catching the exception in the test case instead?
The test case:
public class TestERParser {
#Test(expected=NullPointerException.class)
public void nullSetTrailer() {
ERParser recCurrParse = new ERParser();
recCurrParse.setTrailer(null);
}
}
setTrailer() method within the ERParser Class:
public class ERParser {
private static final String TRAILER_E = "GRAND TOTAL";
private static final String TRAILER_R = "TRAILER";
public String trailerRecord;
/**
* Constructs an ERParser object.
*/
public ERParser() {
this.trailerRecord = null;
this.trailerVals = null;
}
/**
* Populates the trailerRecord field with the summary (trailer) record of the input file.
* #param file Input file
* #throws NullPointerException, FileNotFoundException, IOException
*/
public void setTrailer(File file) {
try {
FileReader fReader = new FileReader(file);
BufferedReader bReader = new BufferedReader (fReader);
String currLine = new String();
readLoop:
while (bReader.ready()) {
currLine = bReader.readLine();
if (currLine.contains(TRAILER_E) || currLine.contains(TRAILER_R)) {
break readLoop;
}
}
this.trailerRecord = currLine.trim();
System.out.println("From setTrailer(): " + this.trailerRecord);
fReader.close();
bReader.close();
} catch (NullPointerException exception) {
exception.printStackTrace();
} catch (FileNotFoundException exception) {
exception.printStackTrace();
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
As you suspected you are catching the NPE inside of your code and it is not being propagated. If you expected your users to catch this exception you should remove this code and adorn your method with throws, to the appropiate classes.
public void setTrailer(File file) throws Exception {
FileReader fReader = new FileReader(file);
BufferedReader bReader = new BufferedReader (fReader);
String currLine = new String();
readLoop:
while (bReader.ready()) {
currLine = bReader.readLine();
if (currLine.contains(TRAILER_E) || currLine.contains(TRAILER_R)) {
break readLoop;
}
}
this.trailerRecord = currLine.trim();
System.out.println("From setTrailer(): " + this.trailerRecord);
fReader.close();
bReader.close();
}
As your code now throws a checked Exception, you will need to update your Junit method slightly, to catch the checked exceptions
#Test(expected=NullPointerException.class)
public void nullSetTrailer() throws Exception {
ERParser recCurrParse = new ERParser();
recCurrParse.setTrailer(null);
}
We can argue about whether or not this catch block means the exception is handled. I would argue that merely printing the stack trace is not handling anything. It might be better to add a throws clause to the method signature and let clients decide what to do with exceptions.
If the method is written that way, it's up to you to test it as-written. You wouldn't have a choice if this was a 3rd party library.
Write the test that throws the exception; succes means trailerRecord is set to null.
Your code has another flaw: close the streams in a finally block. You risk not closing the input stream properly as written.
In your test case are expecting a NullPointerException class. If you catch it, the caller class will not get it. Hence, either you can remove the try/catch blocks or you can rethrow the exception after printing stacktrace :
catch (NullPointerException exception) {
exception.printStackTrace();
throw new NullPointerException();
}
I want to close my stream in the finally block, but it throws an IOException so it seems like I have to nest another try block in my finally block in order to close the stream. Is that the right way to do it? It seems a bit clunky.
Here's the code:
public void read() {
try {
r = new BufferedReader(new InputStreamReader(address.openStream()));
String inLine;
while ((inLine = r.readLine()) != null) {
System.out.println(inLine);
}
} catch (IOException readException) {
readException.printStackTrace();
} finally {
try {
if (r!=null) r.close();
} catch (Exception e){
e.printStackTrace();
}
}
}
Also if you're using Java 7, you can use a try-with-resources statement:
try(BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()))) {
String inLine;
while ((inLine = r.readLine()) != null) {
System.out.println(inLine);
}
} catch(IOException readException) {
readException.printStackTrace();
}
It seems a bit clunky.
It is. At least java7's try with resources fixes that.
Pre java7 you can make a closeStream function that swallows it:
public void closeStream(Closeable s){
try{
if(s!=null)s.close();
}catch(IOException e){
//Log or rethrow as unchecked (like RuntimException) ;)
}
}
Or put the try...finally inside the try catch:
try{
BufferedReader r = new BufferedReader(new InputStreamReader(address.openStream()));
try{
String inLine;
while ((inLine = r.readLine()) != null) {
System.out.println(inLine);
}
}finally{
r.close();
}
}catch(IOException e){
e.printStackTrace();
}
It's more verbose and an exception in the finally will hide one in the try but it's semantically closer to the try-with-resources introduced in Java 7.
In Java 7 you can do this...
try (BufferedReader r = new BufferedReader(...)){
String inLine;
while ((inLine = r.readLine()) != null) {
System.out.println(inLine);
}
} catch(IOException e) {
//handle exception
}
Declaring a variable in the try block requires that it implements AutoCloseable.
Declaring a variable in the try block also limits its scope to the
try block.
Any variable declared in the try block will automatically have close() called when the try block exits.
It's called a Try with resources statement.
Yes it is clunky, ugly and confusing. One possible solution is to use Commons IO which offers a closeQuietly method.
There's a number of questions in the "Related" column on the right hand of this page that are actually duplicates, I advise to look through these for some other ways of dealing with this issue.
Like the answer mentioning the Commons IO library, the Google Guava Libraries has a similar helper method for things which are java.io.Closeable. The class is com.google.common.io.Closeables. The function you are looking for is similarly named as Commons IO: closeQuietly().
Or you could roll your own to close a bunch like this: Closeables.close(closeable1, closeable2, closeable3, ...) :
import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;
public class Closeables {
public Map<Closeable, Exception> close(Closeable... closeables) {
HashMap<Closeable, Exception> exceptions = null;
for (Closeable closeable : closeables) {
try {
if(closeable != null) closeable.close();
} catch (Exception e) {
if (exceptions == null) {
exceptions = new HashMap<Closeable, Exception>();
}
exceptions.put(closeable, e);
}
}
return exceptions;
}
}
And that even returns a map of any exceptions that were thrown or null if none were.
Your approach within finally is correct. If the code that you call in a finally block can possibly throw an exception, make sure that you either handle it, or log it. Never let it bubble out of the finally block.
Within the catch block you are swallowing the exception - which is not correct.
Thanks...
public void enumerateBar() throws SQLException {
Statement statement = null;
ResultSet resultSet = null;
Connection connection = getConnection();
try {
statement = connection.createStatement();
resultSet = statement.executeQuery("SELECT * FROM Bar");
// Use resultSet
}
finally {
try {
if (resultSet != null)
resultSet.close();
}
finally {
try {
if (statement != null)
statement.close();
}
finally {
connection.close();
}
}
}
}
private Connection getConnection() {
return null;
}
source.
This sample was useful for me.
First thing I noticed in your code is curly bracket { } missing from your code if you look at it. also you need to initialize value of r to null so you need to pass null value to object at first so that if condition you have written can do not null condition check and lets you close the stream.