int readByteFromFile(String fileName) throws IOException {
InputStream inputStream = new FileInputStream(fileName);
try {
return inputStream.read();
} finally {
try {
inputStream.close();
} catch (IOException ex) {
log("Hi Ade.");
}
}
}
String readStringFromFile(String fileName) throws IOException {
InputStream inputStream = new FileInputStream(fileName);
try {
DataInputStream dataInput = new DataInputStream(inputStream);
return dataInput.readUTF();
} finally {
try {
inputStream.close();
} catch (IOException ex) {
log("Hi Ade.");
}
}
}
You don't want to have to keep repeating this every time you want to do something similar, but slightly different. How do you refactor the similarities between these methods? The fact is that in Java I see lots of this sort of duplication - because in Java, getting rid of this sort of duplication is often verbose and clunky. However, it is possible, and sometimes very worthwhile.
interface DoWithFile {
Object execute(FileInputStream inputStream) throws IOException;
}
public Object withFile(String fileName, DoWithFile runThis) throws IOException {
FileInputStream inputStream = new FileInputStream(fileName);
try {
return runThis.execute(inputStream);
} finally {
try {
inputStream.close();
} catch (IOException ex) {
DuplicatedCode.log("Hi Ade.");
}
}
}
int readByteFromFile(String fileName) throws IOException {
return ((Integer) withFile(fileName,
new DoWithFile() {
public Object execute(FileInputStream inputStream)
throws IOException {
return inputStream.read();
}
})).intValue();
}
String readStringFromFile(String fileName) throws IOException {
return (String) withFile(fileName, new DoWithFile() {
public Object execute(FileInputStream inputStream)
throws IOException {
DataInputStream dataInput = new DataInputStream(inputStream);
return dataInput.readUTF();
}
});
}
Despite how horrible this looks - it is sometimes worth it.
def readByteFromFile(fileName):
inputStream = file(fileName)
try:
return inputStream.read(1)
finally:
try:
inputStream.close()
except:
log("Hi Ade.")
def readStringFromFile(fileName):
inputStream = file(fileName)
try:
dataInput = DataInputStream(inputStream)
return dataInput.readUTF()
finally:
try:
inputStream.close()
except:
log("Hi Ade.")
Passing a function as a parameter (as a closure) gives:
def withFile(fileName, function):
inputStream = file(fileName)
try:
return function(inputStream)
finally:
try:
inputStream.close()
except:
log("Hi Ade.")
def readByteFromFile(fileName):
def execute(inputStream):
return inputStream.read(1)
return withFile(fileName, execute)
def readStringFromFile(fileName):
def execute(inputStream):
dataInput = DataInputStream(inputStream)
return dataInput.readUTF()
return withFile(fileName, execute)
which hurts much less than the Java version (but slightly more than the Smalltalk version would - but that's another story). [Martin Fowler shows in his article how a Ruby caller of similar code would look "File.open(filename) {|f| doSomethingWithFile(f)}".]
Python doesn't have great syntax for defining closures - it would be nice to be able to define the two "execute" functions anonymously. You can do this for one of the methods using "lambda" but not the other because of the limitations of "lambda". In Smalltalk or Ruby the syntax for this is better. Here's the "lambda" version of the "readByteFromFile" function.
def readByteFromFile(fileName): return withFile(fileName, lambda inputStream: inputStream.read(1))
In Groovy this kind of refactoring becomes less painful on the fingers, and yet still runs entirely within the Java platform.
public withFile(fileName, runThis) {
def inputStream = new FileInputStream(fileName)
try {
return runThis(inputStream)
} finally {
try {
inputStream.close()
} catch (IOException ex) {
DuplicatedCode.log("Hi Ade.")
}
}
}
def readByteFromFile(fileName) {
withFile(fileName){it.read()}
}
def readStringFromFile(fileName) {
withFile(fileName){new DataInputStream(it).readUTF()}
}
Your wish for Java to have better support for Closures just took a step closer to reality... http://gafter.blogspot.com/2006/08/closures-for-java.html
jez
Posted by: jez at August 23, 2006 7:16 PMOooo, tea really is good for you...
http://news.bbc.co.uk/1/hi/health/5281046.stm
:-)
Posted by: jez at August 24, 2006 10:26 AM