Is there a way to catch exceptions without breaking loop in Java? - java

In Java, there's a difference between a loop surrounded with a try-catch block if an exception could be thrown inside the while loop, and a statement surrounded by a try-catch block inside a loop.
For instance, the following code snippets are different:
Snippet 1:
try {
for (File file : files) {
FileInputStream fis = new FileInputStream(file);
System.out.println("OK!");
}
}
catch (FileNotFoundException exc) {
System.out.println("Error!");
}
^This code snippet breaks the loop if a FileNotFoundException is thrown. So if a file cannot be read, then the loop breaks and Java will stop reading further files.
Snippet 2:
for (File file : files) {
try {
FileInputStream fis = new FileInputStream(file);
System.out.println("OK!");
}
catch (FileNotFoundException exc) {
System.out.println("Error!");
}
}
^This code snippet does not break the loop if an exception is thrown, if an exception occurs, the code catches the exception and continues to the next element in files. With other words, it won't stop reading the files.
Now I want to read a certain file in a directory (say bananas.xml), and, unregarded if that file is readable or not—the XML file is a metadata file, which might not be required for the program to run—, read the corresponding directory (which is bananas):
File main = new File("/home/MCEmperor/test");
File fruitMeta = new File(main, "bananas.xml");
FileInputStream fruitInputStream = new FileInputStream(fruitMeta); // This code COULD throw a FileNotFoundException
// Do something with the fruitInputStream...
File fruitDir = new File(main, "bananas");
if (fruitDir.exists() && fruitDir.canRead()) {
File[] listBananas = fruitDir.listFiles();
for (File file : listBananas) {
FileInputStream fis = new FileInputStream(file); // This code COULD throws a FileNotFoundException
// Do something with the fis...
}
}
Now two lines in the snippet above may throw a FileNotFoundException and I don't want to break the loop.
Now is there a way to make one try-catch block with catches both lines if an exception is thrown, but without breaking the for-loop?

How about something like this?
FileInputStream fruitInputStream = getFileInputStream(fruitMeta);
...
fis = getFileInputStream(file);
private static FileInputStream getFileInputStream(File file) {
try {
return new FileInputStream(file);
catch(FileNotFoundException e) {
return null;
}
}

Related

If a runtime exception was thrown after a resource was open - the program close the resource?

I wrote a simple java function that reads a file of Floating-point values and in the case file is not found or
the values that are being read are not floating-point the program throws exceptions.
My question is on the case that the program opened the file but the format of values was not floating-point - can the program close the resources? or should I consider the runtime exception that may happen?
public static ArrayList<Double> readValues(String filename) throws
FileNotFoundException {
var file = new File(filename);
var fileScanner = new Scanner(file);
var doubleList = new ArrayList<Double>();
//In case the values are not of double type and the scanner
while(fileScanner.hasNext())
doubleList.add( Double.parseDouble( fileScanner.next() ) );
fileScanner.close();
return doubleList;
}
o.k I updated the code to use in 'finally' statement
public static ArrayList<Double> readValues(String filename) throws
FileNotFoundException {
var file = new File(filename);
var fileScanner = new Scanner(file);
var doubleList = new ArrayList<Double>();
//In case the values are not of double type and the scanner
try {
while(fileScanner.hasNext())
doubleList.add( Double.parseDouble( fileScanner.next() ) );
}finally {
fileScanner.close();
}
return doubleList;
}
If there are better ideas, I would like to know.
Thanks for the help
Java finally block is always executed whether exception is handled or not.
Please refer to this
A standard approch
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(...);
// do something with the inputstream
} catch (IOException e) {
// handle an exception
} finally { // finally blocks are guaranteed to be executed
// close() can throw an IOException too, so we got to wrap that too
try {
if (fileInputStream != null) {
fileInputStream.close();
}
} catch (IOException e) {
// handle an exception, or often we just ignore it
}
}
From java7: The try-with-resources Statement
From the oracle docs Refer here
You can close resources by using try with resources
try(// open resources here){
// use resources
} catch (FileNotFoundException e) {
// exception handling
}
// resources are closed as soon as try-catch block is executed.

reading variables buried in java exception handling

I am writing a function to take a text file and count how many lines it has while outputting the lines to an array of strings. Doing this I have several exceptions I need to look out for. The class function has several variables that should have a scope throughout the function but when I write a value to the function inside of an exception, the return statement cannot find it. I've moved the declaration around and nothing helps
The value returned "h5Files" "Might not have been initialized" Since I don't know how long the array will be I cannot initialize it to a certain length. I do this within the code and I need a way to tell the return statement that I now have a values
Here is the code
public String[] ReadScanlist(String fileIn){
int i;
String directory ="c:\\data\\"; // "\" is an illegal character
System.out.println(directory);
int linereader = 0;
String h5Files[];
File fileToRead = new File(directory + fileIn);
System.out.println(fileToRead);
try {
FileInputStream fin = new FileInputStream(fileToRead); // open this file
}
catch(FileNotFoundException exc) {
System.out.println("File Not Found");
}
try{
//read bytes until EOF is detected
do {
FileReader fr = new FileReader(fileToRead);// Need to convert to reader
LineNumberReader lineToRead = new LineNumberReader(fr); // Use line number reader class
//
while (lineToRead.readLine() != null){
linereader++;
}
linereader = 0;
lineToRead.setLineNumber(0); //reset line number
h5Files = new String[linereader];
while (lineToRead.readLine() != null){
h5Files[linereader] = lineToRead.readLine(); // deposit string into array
linereader++;
}
return h5Files;
}
while(i !=-1); // When i = -1 the end of the file has been reached
}
catch(IOException exc) {
System.out.println("Error reading file.");
}
try{
FileInputStream fin = new FileInputStream(fileToRead);
fin.close(); // close the file
}
catch(IOException exc) {
System.out.println("Error Closing File");
}
return h5Files;
}
Your code is very very odd. For example these two blocks make no sense:
try {
FileInputStream fin = new FileInputStream(fileToRead); // open this file
}
catch(FileNotFoundException exc) {
System.out.println("File Not Found");
}
try{
FileInputStream fin = new FileInputStream(fileToRead);
fin.close(); // close the file
}
catch(IOException exc) {
System.out.println("Error Closing File");
}
I don't know what you think they do, but besides the first one leaking memory, they do nothing at all. The comments are more worrying, they suggest that you need to do more reading on IO in Java.
Deleting those blocks and tidying the code a (moving declarations, formatting) gives this:
public String[] ReadScanlist(String fileIn) {
String directory = "c:\\data\\";
String h5Files[];
File fileToRead = new File(directory + fileIn);
try {
int i = 0;
do {
FileReader fr = new FileReader(fileToRead);
LineNumberReader lineToRead = new LineNumberReader(fr);
int linereader = 0;
while (lineToRead.readLine() != null) {
linereader++;
}
linereader = 0;
lineToRead.setLineNumber(0);
h5Files = new String[linereader];
while (lineToRead.readLine() != null) {
h5Files[linereader] = lineToRead.readLine();
linereader++;
}
return h5Files;
} while (i != -1);
} catch (IOException exc) {
System.out.println("Error reading file.");
}
return h5Files;
}
My first bone of contention is the File related code. First, File abstracts from the underlying OS, so using / is absolutely fine. Second, there is a reason File has a File, String constructor, this code should read:
File directory = new File("c:/data");
File fileToRead = new File(directory, fileIn);
But it should really be using the new Path API anyway (see below).
So, you declare h5Files[]. You then proceed to read the whole file to count the lines. You then assign h5Files[] to an array of the correct size. Finally you fill the array.
If you have an error anywhere before you assign h5Files[] you have not initialised it and therefore cannot return it. This is what the compiler is telling you.
I don't know what i does in this code, it is assigned to 0 at the top and then never reassigned. This is an infinite loop.
So, you need to rethink your logic. I would recommend throwing an IOException if you cannot read the file. Never return null - this is an anti-pattern and leads to all those thousands of null checks in your code. If you never return null you will never have to check for it.
May I suggest the following alternative code:
If you are on Java 7:
public String[] ReadScanlist(String fileIn) throws IOException {
final Path root = Paths.get("C:/data");
final List<String> lines = Files.readAllLines(root.resolve(fileIn), StandardCharsets.UTF_8);
return lines.toArray(new String[lines.size()]);
}
Or, if you have Java 8:
public String[] ReadScanlist(String fileIn) throws IOException {
final Path root = Paths.get("C:/data");
try (final Stream<String> lines = Files.lines(root.resolve(fileIn), StandardCharsets.UTF_8)) {
return lines.toArray(String[]::new);
}
}
Since I don't know how long the array will be I cannot initialize it
to a certain length.
I don't think an array is the correct solution for you then - not to say it can't be done, but you would be re-inventing the wheel.
I would suggest you use a LinkedList instead, something like:
LinkedList<String> h5Files = new LinkedList<>();
h5Files.add(lineToRead.readLine());
Alternatively you could re-invent the wheel by setting the array to an arbritary value, say 10, and then re-size it whenever it gets full, something like this:
h5Files = new String[10];
if (linereader = h5Files.size())
{
String[] temp = h5Files;
h5Files = new String[2 * linereader];
for (int i = 0; i < linereader; i++)
{
h5Files[i] = temp[i];
}
}
Either one of these solutions would allow you to initialize the array (or array alternative) in a safe constructor, prior to your try block, such that you can access it if any exceptions are thrown
Here is your problem. Please take a look on digested version of your code with my comments.
String h5Files[]; // here you define the variable. It still is not initialized.
try{
..................
do {
h5Files = new String[linereader]; // here you initialize the variable
} while(i !=-1); // When i = -1 the end of the file has been reached
..................
catch(IOException exc) {
// if you are here the variable is still not initialized
System.out.println("Error reading file.");
}
// you continue reading file even if exception was thrown while opening the file
I think that now the problem is clearer. You try to open the file and count lines. If you succeed you create array. If not (i.e. when exception is thrown) you catch the exception but still continue reading the file. But in this case you array is not initialized.
Now how to fix this?
Actually if you failed to read the file first time you cannot continue. This may happen for example if file does not exist. So, you should either return when first exception is thrown or just do not catch it at all. Indeed there is nothing to do with the file if exception was thrown at any phase. Exception is not return code. This is the reason that exceptions exist.
So, just do not catch exceptions at all. Declare your method as throws IOException and remove all try/catch blocks.

Initializing In Try/Catch

I have run into quite a snag while writing my app. Here is my issue:
I am trying to initialize the file input stream like so:
FileInputStream fis
fis = openFileInput(selectedFile);
Then put this 1 line later:
byte[] input = new byte[fis.available()];
Problem is both bits of code need try/catch statements and the second block cannot recognize fis because it was initialized within a try/catch. Here is my code:
private void openFile(String selectedFile) {
String value = "";
FileInputStream fis;
try {
fis = openFileInput(selectedFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
byte[] input = new byte[fis.available()];
} catch (IOException e) {
e.printStackTrace();
}
What should I do? (Thanks in advance)
The best approach in this situation is not to catch IOException at all.
private void openFile(String selectedFile) throws IOException {
FileInputStream fis = openFileInput(selectedFile);
byte[] input = new byte[fis.available()];
It does not make sense to continue after you got FileNotFoundException
Set FileInputStream fis = null; when you first declare the variable.
You could also run your code like this because IOException will also catch the file not found exception.
String value = "";
FileInputStream fis;
try {
fis = openFileInput(selectedFile);
byte[] input = new byte[fis.available()];
} catch (IOException e) {
e.printStackTrace();
}
Set the FileInputStream to a temporary value. null would be the best option, as in:
FileInputStream fis = null;
The reason for this is because if your try statement throws an error, then the fis will never me initialized. Then you'll have problems. If you don't exit the thing entirely, you should also add the statement after the try/catch blocks that tests if the value is null, just so that the program does not throw a null pointer exception.
So maybe something like:
if(fis == null) {
return; // Which will just end the method.
}
Also might want to put the try/catches together (you should still declare the other stuff outside of the try, at least anything you plan on using directly later on in the code) but it just might be more efficient coding wise), as in:
FileInputStream fis = null;
byte[] input = null;
try {
fis = openFileInput(selectedFile);
input = new byte[fis.available()];
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

inside try block a FileIStream variable might not have been initialized error

I am trying to execute this code and I am also providing the valid argument but still I am getting error at line no. 34 and 35 that local variable fin and fout might not have been initialized. How to solve thisenter code here
package maxbj.myTest.p1;
import java.io.*;
public class CopyFile {
public static void main(String[] args)throws IOException {
int i;
FileInputStream fin;
FileOutputStream fout;
try{
//trying to open input file
try{
fin=new FileInputStream(args[0]);
}catch(FileNotFoundException e){
System.out.println("Input file not found");
return;
}
//trying to open output file
try{
fout=new FileOutputStream(args[1]);
return;
}catch(FileNotFoundException e){
System.out.println("Output file cannot be opened or created");
return;
}
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Array index out of bound exception");
}
//code to copy file
try{
do{
i=fin.read();
if(i!=-1) fout.write(i);
}while(i!=-1);
}catch(IOException e){
System.out.println("File Error");
}
fin.close();
fout.close();
}
}
PS- This code is from the book "JAVA COMPLETE REFRENCE"
The compiler is right (and the book is wrong, they should have tried compiling their code before publishing): there is a path through the code when fin remains uninitialized by the time the code reaches the fin.read() line.
Specifically, if ArrayIndexOutOfBoundsException gets thrown in the first outer try/catch block, the fin variable will not be assigned. Adding return to the outer catch block should fix this problem:
try {
...
} catch(ArrayIndexOutOfBoundsException e){
System.out.println("Array index out of bound exception");
return; // <<== Here
}
With the return statement in place, control will never reach the fin.read() unless fin has been initialized, fixing the compile-time error.
A simple way around this is to perform anything which requires fin and fout within the try block. This way you will never be trying to use the streams when they have failed on opening.
try
{
fout = new FileOutputStream(...);
fin = new FileInputStream(...);
// Code goes here
fout.close();
fin.close();
}
catch(FileNotFoundException e)
{
// Error code - e should contain the file name/path
}
Also, it is always good practice to initialise variables when you declare them:
FileOutputStream fout = null;
FileInputStream fin = null;
However, this way (just initialising to null) you programming logic will not cause compiler errors, but if not handled correctly you may get NullPointerExceptions if you try block throws.

Stream Object Initialization

Now I am getting compile time error at line 30 and 38 that 'fin' might not have been initialized. but its perfectly to write it this way
import java.io.*;
class CopyFile {
public static void main(String args[]) throws IOException {
int i;
FileInputStream fin;//can't it be done like this?
FileOutputStream fout= new FileOutputStream(args[1]);
try{
//open input file
try{
fin = new FileInputStream(args[0]);
}
catch(FileNotFoundException e){
System.out.println("Input file Not Found");
return;
}
//open output file
try{
fout = new FileOutputStream(args[1]);
}
catch(FileNotFoundException e){
System.out.println("Error Opening File");
}
}
catch(ArrayIndexOutOfBoundsException e){
System.out.println("usage: Copyfile From to");
}
try{
do{
i = fin.read();
if(i!= -1)
fout.write(i);
}while(i != -1);
}
catch(IOException e){
System.out.println("file error");
}
fin.close();
fout.close();
}
}
I have seen it many time initialized like this. I think its due to the try blocks.
it might miss the initialization due to being in the try block and hence the error?
The problem is that you're not initializing the FileInputStream fin at all. Your code will look like this to the compiler:
FileInputStream fin;
try {
fin = ...
//more code goes here...
} catch (...) {
//exception handling...
} finally {
fin.close(); //fin is not even null for the compiler
}
In order to make the code work, initialize it at least with a null value and check if fin != null before using the close method.
FileInputStream fin = null;
try {
fin = ...
//more code goes here...
} catch (...) {
//exception handling...
} finally {
if (fin != null) {
fin.close(); //fin is not null, at least the JVM could close it
}
}
More info:
Java: Declaring Variables
Uninitialized variables and members in Java
FileInputStream fin=null;
Assign it null or FileInputStream object.
Local variable need to be assigned to some value before being used.
Though in the first try block, you are initializing fin as fin = new FileInputStream(args[0]);, your nested statements confuse the compiler. Just update your declaration as below:
FileInputStream fin = null;
Dont use try catch for an if and vice versa.
Try/catch is for when things go wrong behind your control and that is no part of normal program flow for example writing to a hard disk that is full....
Use if for normal error checking
In your example check your args array with an if block and then initialize your fin.

Categories

Resources