tags:

views:

321

answers:

11

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;
}
}
+11  A: 

I would go for the static version because there is no state.

There is generally no point in a stateless object unless you need it for inheritance purposes (virtual methods).

If the users are likely to want to mock out the functionality then I would prefer an interface over a concrete implementation - the implementor of the interface could not be static so in this case you would have to use an instantiated object.

dice
A: 

Since I don't see any big performance differences I think this is simply a practicality question and in my opinion the static method is alot more practical ;-).

NickDK
+4  A: 

I'd go with the static version.

There's no need for an object as you're not storing state, so why make the caller create an object just to call a method.

Glen
Golden words 'why make the caller create an object just to call a method'!
Binoj Antony
+2  A: 

It all depends on the usage pattern. Maybe you just need to copy something from an InputStream to an OutputStream every now and then? Then it probably won’t matter. However, if you’re doing lots of copying in various environments (network streams, both LAN and WAN, copying files on the local disk) you might be better off when you have the option to select the size of the buffer used for copying.

So, why restrict yourself to only one method? Implement it with object methods and a constructor that takes a buffer size (used for your varying needs), and maybe add a static method to get a pseudo-singleton instance that uses some default buffer size (which is used for the casual copying every now and then).

Bombe
The term `singleton` is a bit misplaced here.
BalusC
It’s more like an optional singleton, you know? Like a singleton but not really. :) (Yeah, maybe I should use some other term. Are there any terms for pseudo-singletons?)
Bombe
Default implementation? :)
Groo
+14  A: 

I'd go with the non-static (instance) version, and supply it to consumers as an explicit dependency with a setter:

  • mocking it out for unit testing is then trivial, so tests of consumers aren't coupled to the implementation;
  • swapping out functionality is straightforward, eg: using a subclass;
  • works nicely with dependency injection systems.

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.

Dan Vinton
+1, mocking out static methods is nigh-on impossible.
Andrzej Doyle
So, here's what I don't understand about this argument: with the instance version, the user will just say `new StreamCopier().copy(in, out)`. How is that any easier to mock out or swap out?
Jason Orendorff
Using static methods also makes it more difficult to create related StreamCopier subclasses in the future.
hallidave
I agree that you *could* have a need for a StreamCopier-Which-Also-Does-Something-Else-While-Copying class (and then you would need to override the method), but this looks much like a simple static helper class. Since it is stateless, you can test it easily. And sometimes a helper class is just that - you don't actually want to create an external interface implementation for every single helper method you are going to call. In this case, I would say: "you ain't gonna need it".
Groo
@Groo I appreciate your point - were this a simple string manipulation helper then you'd probably just write a static helper method and use that. In my mind "Thing that copies streams" sits in the grey area between "things that are obviously static" and "things that are obviously instance". The voting on the answers seems to suggest this too. There are pros and cons to both approaches :)
Dan Vinton
@Jason, I think the idea is that the user of ThingThatUsesStreamCopier is doing other things within the class besides just copying streams.
matt b
@matt: I get that. I guess my question is, how does the momentary existence of a `StreamCopier` object there make the ThingThatUsesStreamCopier easier to test?
Jason Orendorff
+1  A: 

There will be minimal difference in overhead (the static will be allocated once vs allocation on instance basis) especially given that the state consists of a single int. Generally I would rarely go for static classes as they make unit testing difficult. There is little overhead in making classes instance based rather than static (an allocation, zero'ing out memory and calling the constructor - which are all v quick operation) and due to the inability to mock out statics I see little benefit.

Amongst other things static class can also dramatically increase coupling; a static class can be referenced from anywhere as long as the assembly reference is referenced. When it comes to refactoring this can lead to problems (e.g anything the staitc references internally is dragged into the dependency graph etc.).

Ian Gibson
+1  A: 
public static long copy

You don't need an instance to execute the method because you're not storing state, and you are not planning to have subclasses out of this.

I would just add the final keyword.

Auxiliary methods like this are good usages of class methods vs. instance methods.

OscarRyz
+1  A: 

no matter what to use at this time, but you shuld think, what would you need in future. Maybe you have som plans extending buffer operations or something. I'd choose non-static methods.

Piotr M.
A: 

It would depend on the usage. Does the code that calls the copy know what an appropriate buffer size is? It could be that the decision is better off been made outside of that code and a StreamCopier instance is a better thing to pass around as a parameter than a buffer size (e.g. if it turned out that an extra parameter was needed at a later stage no code changes would be needed)

vickirk
+1  A: 

If you go for static you should avoid WET names.

WET stands for write everything twice, thus instead of StreamCopier.copy call it

Copy.stream(in,out)

that way your code reads more like English.

Adrian
I'm not too sure about this, having a "Copy" class seems a little broad. If you needed to write a copy function for a completely unrelated entity, would the method also go in the Copy class?
JonoW
`Streams.copy(in, out)` sounds nice.
Jason Orendorff
@jonow it would. In fact this is they way I organize all my helper methods. `Any.satisfy`, `All.notNull` etc. Of course (unless you have partial classes as in C#) this assumes a closed world, as it might not be given in some public projects.
Adrian
A: 

The static method means coding to a concrete class, not an interface. It means tighter coupling and makes Unit Testing harder. This is where the 'does it contain state' rule falls down.

Vincent Fleetwood