As shown below, there are two straightforward ways I could make a stream copier (bar introducing Apache Commons or similar). Which one should I go for, and why ?
public class StreamCopier {
private int bufferSize;
public StreamCopier() {
this(4096);
}
public StreamCopier(int bufferSize) {
this.bufferSize = bufferSize;
}
public long copy(InputStream in , OutputStream out ) throws IOException{
byte[] buffer = new byte[bufferSize];
int bytesRead;
long totalBytes = 0;
while((bytesRead= in.read(buffer)) != -1) {
out.write(buffer,0,bytesRead);
totalBytes += bytesRead;
}
return totalBytes;
}
}
vs
public class StreamCopier {
public static long copy(InputStream in , OutputStream out)
throws IOException {
return this.copy(in,out,4096);
}
public static long copy(InputStream in , OutputStream out,int bufferSize)
throws IOException {
byte[] buffer = new byte[bufferSize];
int bytesRead;
long totalBytes = 0;
while ((bytesRead= in.read(buffer)) != -1) {
out.write(buffer,0,bytesRead);
totalBytes += bytesRead;
}
return totalBytes;
}
}
Instance method are methods which require an object of its class to be created before it can be called. Static methods are the methods in Java that can be called without creating an object of class. Static method is declared with static keyword.
non-static methods can access any static method and static variable also, without using the object of the class. In the static method, the method can only access only static data members and static methods of another class or same class but cannot access non-static methods and variables.
Static methods are faster but less OOP.
A static factory method is a public static method on the object that returns a new instance of the object. These type of methods share the same benefits as the traditional factory method design pattern. This is especially useful for value objects that don't have a separate interface and implementation class.
I'd go with the non-static (instance) version, and supply it to consumers as an explicit dependency with a setter:
Edit
In response to a (useful!) comment of "how does this help mocking?", here's how it might work:
class ThingThatUsesStreamCopier {
// our copier instance. set in constructor, but might equally use
// a setter for this:
private StreamCopier copier;
public ThingThatUsesStreamCopier(StreamCopier copier) {
this.copier = copier;
}
public void makeCopy(Stream in, Stream out) {
// probably something a little less trivial...
copier.copy(in, out);
}
}
When I come to test ThingThatUsesStreamCopier
, I can create a mock object version of a StreamCopier
and instantiate the ThingThatUsesStreamCopier
using this mock.
By doing so, I have full control over the behaviour of my mock, so my test is decoupled from any real implementations of StreamCopier
. I am only testing the consumer, not the consumer plus the consumed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With