I'm a Pythonista moving into Java/Scala, and I am wondering how to handle the case where you want an exception to be thrown if it occurs. Take the following toy example:
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
In Python I would want this to throw an error if the file isn't found, and let the calling code handle the exception. Is it convention just to re-throw the same exception?
You can make your method throw those exceptions :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
//handle the exception you want to handle
e.printStackTrace();
}
}
}
Just make sure you declare your method with the throws statement, or your compiler might not like it ;)
You can also go this way (let's call this a semi-exception-handling) :
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException, IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
/*Some code to clear some data or to handle the
exception but still throw an exception higher*/
throw e;
}
}
}
You can just do the following...
public class PersonSaver {
private final File file;
public PersonSaver(File file) {
this.file = file;
}
public void save(List<Person> people) throws FileNotFoundException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
}
In any part of your code you can throw a throwable object, such as an Exception.
You should also state it in the method signature, letting the JVM know you'll handle that Exception in a caller's block.
Example:
public void save(List<Person> people) throws FileNotFoundException{
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
}
}
You need to consider if the calling code actually knows what to do with the specific exception. You have defined an API about saving a collection of Person. The calling code knows only about a Person and has no idea ideally where the save is done.
If you throw a lower level exception about the file not found you are leaking the abstraction and you won't be able to change the implementation easily if the calling code is starting to be aware of where things are saved.
The proper approach would be to throw an "business" exception like PersonNotPersisted or PersonNotSaved since this is something the calling code would understand and avoid the low level IO exceptions to the higher layer
If you declare a method to throws an checkedexception you dont need to catch it or any of it subtypes:
public void save(List<Person> people) throws IOExcetion {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
}
}
If you want to handle the exception before you can also do like:
public void save(List<Person> people) throws IOException {
try (ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file))) {
output.writeObject(people);
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
The keyword 'throw' fires the exception to the caller.
Related
i'm struggling to figure out how to use the Closer utility from the guava library. Please see the code below.
One thing is, that the IndexWriter throws an IOException on both object initialization and close(). Therefore, the code in the finally and rethrow blocks is underlined.
The other question is, why do i have to catch Throwable instead of other exception types and do i have to rethrow the errors (i would prefer to log those at the spot)
`
int getDocumentsCount() {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
logger.error(e, e);
return -1;
} finally {
closer.close();
}
}
IndexWriter openIndexWriter() throws IOException {
return new IndexWriter(directory, analyzer, false,
IndexWriter.MaxFieldLength.UNLIMITED);
}
`
Thanks a lot
(stuck with Java 6)
From Guava's own explanation, you have to use Throwable, yes.
Here's their example snippet:
public void foo() throws IOException {
Closer closer = Closer.create();
try {
InputStream in = closer.register(openInputStream());
OutputStream out = closer.register(openOutputStream());
// do stuff with in and out
} catch (Throwable e) { // must catch Throwable
throw closer.rethrow(e);
} finally {
closer.close();
}
}
Note that they catch Throwable and rethrow it directly from the Closer instance.
As to why it is Throwable and not, let's say IOException or RuntimeException, it's because the Closer must know that an error occurred so that it can close the resources properly. All is only a matter of doing things proper. So it can work if you don't do it properly, but it's not guaranteed.
Not that if your method can throw MyOwnCheckedException, for instance, you have to declare them:
} catch (Throwable t) {
throw closer.rethrow(e, MyOwnCheckedException.class);
} finally {
closer.close();
}
Java 7 example, for comparison:
public void foo() throws IOException {
try (InputStream in = openInputStream();
OutputStream out = openOutputStream();
// do stuff with in and out
}
}
If you compare the Closer example with the Java 7 example, you can see that I still have to declare the IOException in the method signature.
For your case, this is what you have to do:
int getDocumentsCount() {
try {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
closer.rethrow(e);
} finally {
closer.close();
}
} catch (IOException e) {
logger.error(e, e);
return -1;
}
}
To avoid try-pyramids, I'd do the following:
int getDocumentsCount() {
try {
return doGetDocumentsCount();
} catch (IOException e) {
logger.error(e, e);
return -1;
}
}
int doGetDocumentsCount() throws IOException {
Closer closer = Closer.create();
try {
IndexWriter iwriter = closer.register(openIndexWriter());
return iwriter.numDocs();
} catch (Throwable e) {
closer.rethrow(e);
} finally {
closer.close();
}
}
For one of my projects, I implement a Java 7 FileSystem over the Box API Java SDK (the new one).
However, for downloading files, when you want to have a stream to the content, it only provides methods taking OutputStream as an argument; specifically, I am using this one at the moment.
But this doesn't sit well with the JDK API; I need to be able to implement FileSystemProvider#newInputStream()... Therefore I elected to use Pipe{Input,Output}Stream.
Moreover, since the Box SDK API methods are synchronous (not that it matters here), I wrap them in a Future. My code is as follows (imports ommitted for brevity):
#ParametersAreNonnullByDefault
public final class BoxFileInputStream
extends InputStream
{
private final Future<Void> future;
private final PipedInputStream in;
public BoxFileInputStream(final ExecutorService executor,
final BoxFile file)
{
in = new PipedInputStream(16384);
future = executor.submit(new Callable<Void>()
{
#Override
public Void call()
throws IOException
{
try {
file.download(new PipedOutputStream(in));
return null;
} catch (BoxAPIException e) {
throw BoxIOException.wrap(e);
}
}
});
}
#Override
public int read()
throws IOException
{
try {
return in.read();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int read(final byte[] b)
throws IOException
{
try {
return in.read(b);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int read(final byte[] b, final int off, final int len)
throws IOException
{
try {
return in.read(b, off, len);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public long skip(final long n)
throws IOException
{
try {
return in.skip(n);
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public int available()
throws IOException
{
try {
return in.available();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public void close()
throws IOException
{
IOException streamException = null;
IOException futureException = null;
try {
in.close();
} catch (IOException e) {
streamException = e;
}
try {
future.get(5L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
futureException = new BoxIOException("donwload interrupted", e);
} catch (ExecutionException e) {
futureException = new BoxIOException("download failure",
e.getCause());
} catch (CancellationException e) {
futureException = new BoxIOException("download cancelled", e);
} catch (TimeoutException e) {
futureException = new BoxIOException("download timeout", e);
}
if (futureException != null) {
if (streamException != null)
futureException.addSuppressed(streamException);
throw futureException;
}
if (streamException != null)
throw streamException;
}
#Override
public synchronized void mark(final int readlimit)
{
in.mark(readlimit);
}
#Override
public synchronized void reset()
throws IOException
{
try {
in.reset();
} catch (IOException e) {
future.cancel(true);
throw new BoxIOException("download failure", e);
}
}
#Override
public boolean markSupported()
{
return in.markSupported();
}
}
The code consistenly fails with the following stack trace (that is in int read(byte[]):
Exception in thread "main" com.github.fge.filesystem.box.exceptions.BoxIOException: download failure
at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:81)
at java.nio.file.Files.copy(Files.java:2735)
at java.nio.file.Files.copy(Files.java:2854)
at java.nio.file.CopyMoveHelper.copyToForeignTarget(CopyMoveHelper.java:126)
at java.nio.file.Files.copy(Files.java:1230)
at Main.main(Main.java:37)
[ IDEA specific stack trace elements follow -- irrelevant]
Caused by: java.io.IOException: Pipe broken
at java.io.PipedInputStream.read(PipedInputStream.java:322)
at java.io.PipedInputStream.read(PipedInputStream.java:378)
at java.io.InputStream.read(InputStream.java:101)
at com.github.fge.filesystem.box.io.BoxFileInputStream.read(BoxFileInputStream.java:78)
... 10 more
But when it fails, the download is already complete...
OK, the thing is, I can grab the file size and hack around it but I'd prefer not to if at all possible; how can I modify this code so as to avoid EPIPE?
The SDK also provides BoxAPIRequest and BoxAPIResponse classes that let you make manual requests for advanced use-cases. These classes still automatically handle authentication, errors, back-off, etc. but give you more granular control over the request.
In your case, you could do make a download request manually by doing:
// Note: this example assumes you already have a BoxAPIConnection.
URL url = new URL("files/" + file.getID() + "/content")
BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
BoxAPIResponse response = request.send();
InputStream bodyStream = response.getBody();
// Use the stream.
response.disconnect();
Well, I found the solution, although I am not very satisfied with it...
Since I can know the file size which I try to open an inputstream on, I just pick the size and decrease it by the amount of bytes read -- unless the size reaches 0, in this case all read methods return -1.
I have a HashMap where i store last read time of multiple sources which i needs to be backed up to a file. The same hashmap is updated regularly and should be backed up every time.
I am using ObjectOutputStream for this, as the same object is updated i was doing a reset() on the ObjectOutputStream, so that the file is updated, but with this is see and for every writeObject() a new line is written to the file this should be because the object is appended to the file. My service is long running service, so i can't afford the object to be appended every time as that will cause the file to become huge.
Here is a snippet of my code
public void open() throws WCException {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(bookmarkFile));
bookmarks = (HashMap<String, Long>) objectInputStream.readObject();
objectInputStream.close();
} catch (ClassNotFoundException | IOException e) {
}
try {
fileOutputStream = new FileOutputStream(bookmarkFile);
objectOutputStream = new ObjectOutputStream(fileOutputStream);
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public void close() throws WCException {
try {
objectOutputStream.close();
fileOutputStream.close();
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public synchronized void write() throws WCException {
try {
objectOutputStream.writeObject(bookmarks);
objectOutputStream.reset();
} catch (IOException e) {
throw new WCException("Bookmarker", e.getCause());
}
}
public synchronized void update(HashMap<String, Long> bookmark) {
for (Map.Entry<String, Long> entry : bookmark.entrySet()) {
if (!bookmarks.containsKey(entry.getKey()))
bookmarks.put(entry.getKey(), entry.getValue());
else {
long last = bookmarks.get(entry.getKey());
if (last < entry.getValue())
bookmarks.put(entry.getKey(), entry.getValue());
}
}
}
I want something with which there is always a simple object in the file, which is latest. I am even ok with going away from ObjectOutputStream.
I am trying to do some kind of serialization where I can directly read and write objects from file.
To start of I just tried to write a character to file and tried to read it. This keeps giving me EOF exception always.
I am trying it on a Android device. Here is my code:
public class TestAppActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
WriteToFile();
Load();
} catch (Exception e) {
e.printStackTrace();
}
}
public void Load () throws IOException
{
InputStream fis;
ObjectInputStream in = null;
try {
fis = new FileInputStream(Environment.getExternalStorageDirectory() + "\\test2.ser");
in = new ObjectInputStream(fis);
char temp = in.readChar();
} catch (IOException e) {
e.printStackTrace();
} finally {
in.close();
}
}
public static void WriteToFile() throws Exception {
try {
OutputStream file = new FileOutputStream(Environment.getExternalStorageDirectory() + "\\test2.ser");
ObjectOutput output = new ObjectOutputStream(file);
try {
output.writeChar('c');
} finally {
output.close();
}
} catch (IOException ex) {
throw ex;
}catch (Exception ex) {
throw ex;
}
}
}
In this case, EOFException means there is no more data to be read, which (again in this case) can only mean that the file is empty.
Why are you using ObjectInput/OutputStreams but only writing chars? You'd be better off with DataInput/OutputStreams for that usage.
Also there is no point in catching exceptions only to rethrow them.
Also there is no point in reading a char from a file unless you are going to put it somewhere other than in a local variable that isn't even returned by the method.
I have imported this code in my sample project with following change.
i replaced "\\test2.ser"with "/test2.ser" and it worked. please try this.
I am using a buffered writer and my code, closes the writer in the finally block. My code is like this.
...........
BufferedWriter theBufferedWriter = null;
try{
theBufferedWriter =.....
....
......
.....
} catch (IOException anException) {
....
} finally {
try {
theBufferedWriter.close();
} catch (IOException anException) {
anException.printStackTrace();
}
}
I have to use the try catch inside the clean up code in finally as theBufferedWriter might also throw an IOException. I do not want to throw this exception to the calling methos. Is it a good practice to use a try catch in finally? If not what is the alternative? Please suggest.
Regards,
Hiral
A somewhat nicer way to do this is to use IOUtils.closeQuiety from Apache commons-io. It keeps your code tidy and eliminates some of the boilerplate that's inherent in Java.
You code then becomes:
BufferedWriter theBufferedWriter = null;
try{
theBufferedWriter = ...
...
} catch (IOException anException) {
...
} finally {
IOUtils.closeQuietly(theBufferedWriter);
}
Much nicer and more expressive.
In pre Java 7, I'd say what you have written is the best solution.
In Java 7 and onwards you have Automatic Resource Management intended to simplify these things. With this feature, you can do
BufferedWriter theBufferedWriter = null;
try (BufferedWriter theBufferedWriter = ...) {
....
......
.....
} catch (IOException anException) {
....
}
Or you can use Lombok and the #Cleanup annotation and you shall never write a try catch inside finally again.
This is how you would normally write it (Note the throws IOException):
//Vanilly Java
import java.io.*;
public class CleanupExample {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]);
try {
OutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
out.close();
}
} finally {
in.close();
}
}
}
Now with Lombok you just write #Cleanup on the streams
import lombok.Cleanup;
import java.io.*;
public class CleanupExample {
public static void main(String[] args) throws IOException {
#Cleanup InputStream in = new FileInputStream(args[0]);
#Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}
This is what we will have to live with until Java 7 and ARM Blocks.
It's OK but you should test if theBufferedWriter is not null before closing it.
You could also do:
BufferedWriter theBufferedWriter;
try {
theBufferedWriter = new ...
try {
...
} finally {
try {
theBufferedWriter.close();
} catch (IOException closeException) {
closeException.printStackTrace();
}
}
} catch (IOException anException) {
...
}
or:
BufferedWriter theBufferedWriter;
try {
theBufferedWriter = new ...
} catch (IOException createException) {
// do something with createException
return; // assuming we are in a method returning void
}
try {
...
} catch (IOException anException) {
...
// assuming we don't return here
}
try {
theBufferedWriter.close();
} catch (IOException closeException) {
closeException.printStackTrace();
}
but mostly I do such operations (e.g. writing a file) in a dedicated method and prefer to throw the/an Exception so the caller can handle it (e.g. asking for another file, stopping the application, ...):
void someMethod(...) throws IOException {
BufferedWriter theBufferedWriter = new ...
try {
...
} catch (IOExcepption anException) {
try {
theBufferedWriter.close();
} catch (IOException closeException) {
closeException.printStackTrace();
// closeException is not thrown, anException represents the main/first problem
}
throw anException;
}
theBufferedWriter.close(); // throws the Exception, if any
}
Please note: English is not my first nor my second language, any help would be appreciated
It's ok to put a try-catch in a finally. It is the tool that does what you want to do. However, I feel the thrown IOException on close is uncommon enough that I would allow it to suppress any exception in the body like so.
try {
BufferedWriter writer = .....
try {
.....
} finally {
writer.close();
}
} catch (IOException e) {
....
}