简体   繁体   中英

Issues in scope of variables while using try-catch in Java

I have a class PDF which implements an interface fileReader .

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class PDF implements fileReader {
    @Override
    public byte[] readFile(File pdfDoc) {
        if (!pdfDoc.exists()) {
            System.out.println("Could not find" + pdfDoc.getName() + " on the specified path");
            return null;
        }
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(pdfDoc);
        } catch (FileNotFoundException e) {
            System.out.println("");
            e.printStackTrace();
        }
        byte fileContent[] = new byte[(int) pdfDoc.length()];
        try {
            fin.read(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fileContent;
    }
}

import java.io.File;
public interface fileReader {
    <T> T readFile(File fileObject);
}

I notice that there are scope issues for variables fin .

Another implementation I made was:

public byte[] readFile1(File pdfDoc) {
        if (!pdfDoc.exists()) {
            System.out.println("Could not find" + pdfDoc.getName() + " on the specified path");
            return null;
        }
        FileInputStream fin = null;
        try {
            fin = new FileInputStream(pdfDoc);
            byte fileContent[] = new byte[(int) pdfDoc.length()];
            try {
                fin.read(fileContent);
            } catch (IOException e) {
                System.out.println("");
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            System.out.println("");
            e.printStackTrace();
        }
        return fileContent;
    }

But now I could not access fileContent .

How can I combine the try-catches so that I don't have scope problems? Can there be a better design approach to this problem? I have to make functions for reading three different types of file.

Since Java 7 you can combine the try-catch as follows:

    FileInputStream fin = null;
    try {
        fin = new FileInputStream(pdfDoc);
        byte fileContent[] = new byte[(int) pdfDoc.length()];
        fin.read(fileContent);
    } catch (IOException | FileNotFoundException e) {
        System.out.println("");
        e.printStackTrace();
    }

Which, in my opinion, makes the code cleaner and variable scopes more obvious.

You can nest the try catch statements:

    try {
       FileInputStream fin = new FileInputStream(pdfDoc);
       byte fileContent[] = new byte[(int) pdfDoc.length()];
       try {
          fin.read(fileContent);
          return fileContent;
       } catch (IOException e) {
         e.printStackTrace();
       } finally {
         fin.close();
       }

    } catch (FileNotFoundException e) {
        System.out.println("");
        e.printStackTrace();
    }
    return null;

Note that I added a close() in a finally clause to clean up. And also returning null is probably not what you want in case of error, but that's application specific.

You can have one try with multiple catch blocks.

try {
    //do stuff
}
catch (FileNotFoundException e) {
        System.out.println("");
        e.printStackTrace();
}
catch (IOException e) {
        e.printStackTrace();
}

You can modify this part:

        FileInputStream fin = null;
        try {
            fin = new FileInputStream(pdfDoc);
        } catch (FileNotFoundException e) {
            System.out.println("");
            e.printStackTrace();
        }
        byte fileContent[] = new byte[(int) pdfDoc.length()];
        try {
            fin.read(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
        }

By

{
......
       FileInputStream fin = null;
       byte fileContent[]=null;
        try {
            fin = new FileInputStream(pdfDoc);
            fileContent = new byte[(int) pdfDoc.length()];
            fin.read(fileContent);
        } catch (FileNotFoundException e) {
            System.out.println("");
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        }
        return fileContent
    }

I would write like this:

public byte[] readFile(File pdfDoc) {
    if (!pdfDoc.exists()) {
        System.out.println("Could not find" + pdfDoc.getName() + " on the specified path");
        return null;
    }
    FileInputStream fin = null;
    byte fileContent[] = new byte[(int) pdfDoc.length()];

    try {
        fin = new FileInputStream(pdfDoc);
        fin.read(fileContent);
    } catch (FileNotFoundException e) {
        System.out.println("");
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (null != fin) {
            fin.close();
        }
    }   
    return fileContent;
}

Since Java 7, there is a nice utility methods for reading the entire content of a file:

return Files.readAllBytes(pdfFile.toPath());

This method will open and close the FileInputStream for you, so you don't need to do this yourself. It throws an IOException if something goes wrong. Usually, it's best to let this exception propagate to the caller, but if you really want to return null in that case, you can accomplish this as follows:

try {
    return Files.readAllBytes(pdfFile.toPath());
} catch (IOException e) {
    e.printStackTrace();
    return null;
}

This also has the nice advantage that the value returned in that case is explicit - or did you really mean to return an array filled with 0 values if the file could no longer be found, as your current code does?

Note that since NoSuchFileException is a subclass of IOException, the catch block will handle both. If you want to handle it differently you can write a separate catch block for the NoSuchFileException:

try {
    return Files.readAllBytes(pdfFile.toPath());
} catch (NoSuchFileException e) {
    System.err.println("Oh no, the file has disappeared.");
    e.printStackTrace();
    return null;
} catch (IOException e) {
    System.err.println("The file exists, but could not be read.");
    e.printStackTrace();
    return null;
}

Finally, I should probably mention that your file reading code is incorrect, as InputStream.read() does not necessarily read the entire file at once. That's why it returns the number of bytes read so you can invoke it again for the rest of the file. But as I said, since Java 7 you don't need to use such low level APIs (unless the file is too big to fit into memory, of course).

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM