Consider the following code
public class foo {
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.read();
}
}
and
public class MyClass {
private BufferedWriter verb;
private String vFile;
MyClass()
{
try {
verb = new BufferedWriter(new FileWriter(vFile));
} catch(IOException e) {
System.out.println("Internal error1");
System.out.println(e.getMessage());
}
}
public void read()
{
// read a file and create an array
verb.write("Array created"); // ERROR
}
}
As you can see the write is not placed in a try..catch block. I can write a catch for that, but MyClass has many methods and verb.write is used heavily. I also can write public void read() throws IOException to throw the exception to the the caller, main(). Still I have to put mc.read() in a try..catch block. Since MyClass has numerous methods, then I have to put all of them in a catch block in the main().
So, is there a better way to handle that? Is it possible to redirect all exceptions related to verb to the constructor, MyClass() where a try..catch is defined?
One approach is to make your own "safe" wrapper around BufferedWriter (for that matter, any kind of Writer) and handle I/O errors there:
class SafeWriter {
private final Writer writer;
public SafeWriter(Writer writer) {
this.writer = writer;
}
public void write(int n) {
try {
writer.write(n);
} catch (IOException e) {
handleException(e);
}
}
public void write(String s) {
try {
writer.write(s);
} catch (IOException e) {
handleException(e);
}
}
... // Provide wrappers for other methods here
private void handleException(IOException e) {
...
}
}
Now you can use write methods on your new class to handle exceptions in a uniform way inside the class:
private SafeWriter verb;
...
verb = new SafeWriter(new BufferedWriter(new FileWriter(vFile)));
Related
I have just read, that in Java the classes PrintStream and PrintWriter don't throw checked exceptions. Instead they are using a kind of an error flag which I can read invoking the method boolean checkError() (API link).
Now, I am asking myself how to find out the reason why the exception occurred. The information that there was an exception is sometimes maybe not enough, or?
Based on the source code, it looks like they discard the exception. All of the catch blocks look like this:
try {
...
}
catch (IOException x) {
trouble = true; // (x is ignored)
}
So the most straightforward solution is probably to not use PrintStream, if possible.
One workaround could be to extend PrintStream and wrap the output in another OutputStream which captures the exception before PrintStream catches (and discards) it. Something like this:
package mcve.util;
import java.io.*;
public class PrintStreamEx extends PrintStream {
public PrintStreamEx(OutputStream out) {
super(new HelperOutputStream(out));
}
/**
* #return the last IOException thrown by the output,
* or null if there isn't one
*/
public IOException getLastException() {
return ((HelperOutputStream) out).lastException;
}
#Override
protected void clearError() {
super.clearError();
((HelperOutputStream) out).setLastException(null);
}
private static class HelperOutputStream extends FilterOutputStream {
private IOException lastException;
private HelperOutputStream(OutputStream out) {
super(out);
}
private IOException setLastException(IOException e) {
return (lastException = e);
}
#Override
public void write(int b) throws IOException {
try {
super.write(b);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void write(byte[] b) throws IOException {
try {
super.write(b);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
try {
super.write(b, off, len);
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void flush() throws IOException {
try {
super.flush();
} catch (IOException e) {
throw setLastException(e);
}
}
#Override
public void close() throws IOException {
try {
super.close();
} catch (IOException e) {
throw setLastException(e);
}
}
}
}
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.
A coworker just unsettled me concerning finally blocks. He claimed that if multiple resources are closed inside a finally block, I do not have to worry about exception handling.
So if I close my resources like this
try {
// do stuff
} catch(Exception e) {
// handle stuff
} finally {
resource1.close();
resource2.close();
}
and an exception occurs at resource1.close(), will the close() method of resource2 get called?
A simple check would confirm:
class MyResource implements AutoCloseable {
private final String name;
MyResource(String name) { this.name = name; }
#Override public void close() throws IOException {
System.out.println("Closing " + name);
throw new IOException();
}
}
public static void main(String[] args) throws IOException {
MyResource a = new MyResource("a");
MyResource b = new MyResource("b");
try {
} finally {
a.close();
b.close();
}
}
This would print "Closing a" and then print a stack trace; "Closing b" would not be printed. In contrast:
try (MyResource a = new MyResource("a");
MyResource b = new MyResource("b")) {
}
would print both.
That depends. If the only exception throwing things (explicitly or potentially) you have inside your try-catch block are close operations, you wouldn't need exception handling. However, most of the times, the close operations are themselves declared as throwing exceptions, thus, you'd need to put them inside a try-catch block anyway.
Is there a way to save the whole console output to a file when multithreading? I'm working with 5 threads. I had this idea that i can put a printstream in the run-method.
example:
public void run() {
try{
PrintStream out = new PrintStream(file);
stopExecute stop = new stopExecute();
Thread t = new Thread(stop);
Scanner in = new Scanner(System.in);
t.start();
while (!in.hasNextLine())
{
classThatUsingMultipleThrads();
System.out.println("Finished");
anotherClassThatUsingThreads();
System.out.println("Finished");
}
System.out.prinln("User stopped the execution");
stop.keepRunning = false;
System.setOut(out);
}
catch(IOException e){System.out.println(e);}
Problem here is that it's only saving the output "User stoped the execution" and everything in the whileloop are not saved. Or the outputstream from other classes.
I've tried to put the
System.setOut(out);
in the while-loop, but didn't help.
Edit: Spell correction
try {
System.setOut(new PrintStream(new File("output-file.txt")));
}
catch (Exception e) {
e.printStackTrace();
}
thanks to: System.out to a file in java
You should probably look into using a logging library such as Log4J. However you could also use something like a TeeOutputStream. This type of output stream writes to 2 other streams when called. A few libraries have great implementations but you can also write one yourself. I whipped this one up real quick.
You could set the output stream for your entire program in your main method to use this TeePrintStream, then all calls to System.out.* will write data to the usual System.out and your FileOutputStream.
Theres also an implementation of the TeePrintStream here http://www.java2s.com/Code/Java/File-Input-Output/TeePrintStreamteesallPrintStreamoperationsintoafileratherliketheUNIXtee1command.htm
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
public class SO34042494 {
public static void main(String[] args) throws FileNotFoundException {
System.setOut(new TeePrintStream(System.out, new FileOutputStream(new File("x:\\output.txt"))));
System.out.println("Check check");
System.out.println("1");
System.out.println(2);
System.out.println(3L);
}
public static class TeePrintStream extends PrintStream {
private final OutputStream tee;
public TeePrintStream(PrintStream original, OutputStream tee) {
super(original);
this.tee = tee;
}
#Override
public void write(byte[] b) throws IOException {
super.write(b);
tee.write(b);
}
#Override
public void write(byte[] buf, int off, int len) {
super.write(buf, off, len);
try {
tee.write(buf, off, len);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
public void write(int b) {
super.write(b);
try {
tee.write(b);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
public synchronized void close() {
try {
tee.close();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
super.close();
}
}
}
}
The TeePrintStream I have here is something I just threw together, please if your going to use this in a production project polish it up and test it thoroughly
Okej i think i solved it. In my main i just did like this:
public static void main(String[] args) {
Prinstream out = new Prinststream(file);
/*
Do some things like start threads, call objects etc..
.
.
.
.
*/
System.setOut(out);
I think that when all threads are started and doing their things(i do assign a object to each thread) the printstream will catch every console-output that occurs in other classes.
This didn't work before i edited my stopExecute class.
public class stopExecute implements Runnable {
Scanner scan = new Scanner(System.in);
private Object[] obj;
public stopExecute(Object[] obj)
{
this.obj = obj;
}
public void run() {
while(true){
stop();
}
}
public void stop() {
if(scan.hasNextLine()){
System.out.println("Stopped");
System.exit(0);
}
}
}
Thank you for your help guys. I will look into your suggestions and try them. In this solution i'm unable to use Log4J. But i will definitely check it out.
I don't know if my mind just fools me or this is really not working.
I need different type of Logging-classes so I created a abstract-class, the only definition that all classes will have the same is the way the writeToLog is handled:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected FileWriter fw;
public void writeToLog(String message) {
if(fw != null) {
try {
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message;
fw.write(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The concrete sub-classes will implement rest of the logic in their constructor, ie one of them:
public class JitterBufferLogger extends LoggerTemplate {
public JitterBufferLogger() {
super();
filename += new SimpleDateFormat("yyyyddMMhhmm'.log'").format(new Date());
if(!new File("log/").exists())
new File("log").mkdir();
logfile = new File(filename);
try {
logfile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try {
fw = new FileWriter(logfile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
But when I debug I can see that when calling the writeToLog for a specific logger, it jumps into the LoggerTemplate method, and therefore fw and logfile are null. So it's not working.
Isn't it supposed to work or do I just mess something a bit up and should go into weekend ;-)
It should work, it is normal, that the debugger stepped into the LoggerTemplate class upon entering the writeToLog() method. What is strange that the attributes in the base class have null values.
I have tested your code with the following short test program:
public class Test {
public static void main(String[] args) {
LoggerTemplate lt = new JitterBufferLogger();
lt.writeToLog("Hello");
}
}
After adding fw.flush() to the LoggerTemplate.writeToLog() method just after the fw.write() call, it worked for me, the log file had been created and it contained the log message.
Maybe the new File("log").mkdir() or some other calls throw an exception which you cannot see, because stderr had been redirected somewhere.
So what may be missing?
- filewriter flushing could have helped.
- I can't reproduce the null values with the original code, don't know what happened.
- but as everybody, including me, said: it should work and it does.
Why was nothing in the logfile?
- maybe the flush of fw was missing..
anyhow I wrapped it with a Printwriter:
public abstract class LoggerTemplate {
protected String filename ="log/";
protected File logfile;
protected PrintWriter pw;
public void writeToLog(String message) {
try {
pw = new PrintWriter(new FileWriter(logfile,true));
message = new SimpleDateFormat("dd-MM-hh:mm").format(new Date()) + " " + message + "\n";
pw.write(message);
pw.flush();
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
and now it's working like it should and was expected to be.
Note that the fw instantiation in the concrete sub-classes is not needed anymore.