问题
I am using the Stream API introduced in Java 8 to run a method for each string in a list.
public boolean initFile() throws IOException
{
if (this.outFile.exists()) {
this.outFile.delete();
}
return this.outFile.createNewFile();
}
public void writeStringToFile(String str, boolean addNewLine) throws IOException
{
if (this.mode != FileMode.READ) {
if (this.initFile()) {
FileWriter fileWriter;
if (this.mode == FileMode.APPEND)
fileWriter = new FileWriter(outFile.getAbsolutePath(), true);
else
fileWriter = new FileWriter(outFile.getAbsolutePath());
fileWriter.write(str);
if (addNewLine)
fileWriter.write("\n");
fileWriter.close();
} else {
throw new IOException("IO Error: The file could not be initialized.");
}
} else {
throw new IOException("Cannot write to a file with the mode FileMode.READ");
}
}
public void writeListToFile(List<String> strings, boolean addNewLine) throws IOException
{
strings.stream().forEach(s -> this.writeStringToFile(s, addNewLine)); // Unhandled IOException from writeStringToFile
}
As you can see, the method signature states to throw all IOExceptions and the writeToString method inside the stream has the potential to throw an IOException. However, the Java compiler is giving me an error stating that there is an unhandled IOException on the stream line.
Why would the exception inside the stream not get thrown like any other exception inside the method? Is there any way that I can remedy this without putting a try-catch statement in the forEach lambda expression?
回答1:
you have to use try catch in you writeListToFile method like this:
public void writeListToFile(List<String> strings, boolean addNewLine) throws Exception {
strings.stream().forEach(s -> {
try {
writeStringToFile(s, addNewLine);
} catch (IOException ex) {
//you can Log it immediately or throw ex;
Logger.getLogger(C.class.getName()).log(Level.SEVERE, null, ex);
}
});
// Unhandled IOException from writeStringToFile
}
why? look at this point s -> {}.Here {} means that compiler make new Interface (Consumer)
void forEach(Consumer<? super T> action);
and new Class implements this interface and pass s parameter to it's accept method.Can you throw Exception of new Class in your method? No.So you have to try catch of every item of foreach
回答2:
Don’t reinvent the wheel. Use the features offered by the Java API.
public void writeListToFile(List<String> strings, boolean addNewLine) throws IOException
{
if(this.mode == FileMode.READ)
throw new IOException("Cannot write to a file with the mode FileMode.READ");
Files.write(outFile.toPath(), addNewLine? strings:
Collections.singleton(strings.stream().collect(Collectors.joining())),
this.mode==FileMode.APPEND? StandardOpenOption.APPEND: StandardOpenOption.CREATE);
}
Files.write will write all lines of an Iterable
(which includes Collection
s) and that’s it. Your obstacle of supporting the addNewLine
option can be solved by collecting all String
s into one in the case, addNewLine
is false
, hence, there will be no line-feeds between them then. Otherwise, Files.write
will append line-feeds to every string.
There is no point in manually dealing with testing for the existence of files or trying to delete or create them. Regardless of whether you create your own Writer
or use Files.write
, these implementations will already report failures regarding existence/non-existence or failed attempts of creating the target file via IOException
s, so you don’t need to do it yourself.
Even worse, whatever File.exists()
, File.delete()
, or File.createNewFile()
may return, is already an outdated information upon your subsequent I/O operation, e.g. creating/using a Writer
, and does not guaranty anything about whether the subsequent operation will succeed or fail.
来源:https://stackoverflow.com/questions/29838774/unhandled-ioexception-inside-java-list-stream-foreach-lambda-expression