Here's an example of a utility method:
public static Long getFileSize(String fileString) {
File file = new File(fileString);
if (file == null || !file.isFile())
return null;
return file.length();
}
Is it a good practise to pass a String rather than a File to a method like this? In general what reasoning should be applied when making utility methods of this style?
It depends on the utility expected from the client side. In case the client side already has a file object and wants to fetch the filesize, the client side developer is forced to extract the file path and pass it to the utility method. In order to avoid it, I would provide overloaded methods 1) with File 2) File Path String
Also, In case the file is unavailable, I would throw an exception than return null.
I'd go with a File. It feels a little OOP correct to me: more typesafe (Strings are so 'general' in Java...) and semantically expressive: if you are dealing with files, well then pass a File object.
Recall that in Java a File object represents not really a file in itself (its content) but rather its path: "An abstract representation of file and directory pathnames" (it can even be the path of a non-existent file) and that's almost exactly what you need here.
This can only be a limitation in a few cases: if the "file" is actually some kind of pseudo-file or resource, for example inside a jar file. An alternative I have found useful is a URI, which (conceptually) includes a File as a special case, but also other resources.
And if you decide to stick with the two alternatives (String or File), I emphatically don't recommend to name the methods the same. Method overloading can be a pain, use it only when it gives you a tangible benefit.
There are a number of considerations:
Utility methods exist to reduce the amount of repetitive boiler plate code in your app, hence making the code more readable and reducing the number of potential bugs. It makes sense to cater for most common usage patterns, i.e. if most of the time you have a string describing a file - pass the string. Most of the benefit comes from having a utility method in a first place, not getting the optimal signature that is 100% future-proof.
Passing a file instead of a string provides stronger typing, that is to say more of you code can be checked at compile time safeguarding against typos. Make the compiler do the work for you, use the benefits of strong typing.
Passing a file means that you could pass any kind of File object, possibly a bespoke in-memory file object without having to change the utility method to handle the bespoke file descriptor.
Passing a string could help when you have to deal a lot with OS file paths and you just want to check the size with a minimum number of lines.
At the end you could have several overloaded utility methods at a very low cost. This scenario is exactly the reason for existence of method overloading as a language feature. See what naturally works in you code base. Code is malleable and this is not one of these design decisions you'd have to live with forever, unless you're building an API for other people to use.
You could also want to change the name to be a bit more descriptive, for instance
using convention originally suggested by Joel Spolsky.