Reputation: 761
I have a file that I want to create, so I want to ensure that all of its parent directories are in place before it is created (or I will get an error).
File fileA = fileB.getParentFile();
Now, if fileB does in fact have a parent file, fileA will contain an actual file object. However, if fileB does not have a parent, fileA will be equal to null, and calling createNewFile() on fileA will result in a NullPointerException error. Thus, the only way to create fileA safely would be to then do the following:
if (fileA != null) {
fileA.mkdirs();
{
fileB.createNewFile();
However, the general consensus seems to be that you should never use the != null check in your code because it is poor practice. Are there exceptions to this rule, and is this one of them? Or is there a better way I could phrase this code?
Upvotes: 0
Views: 2316
Reputation: 11
solar
has already answered the more general question of whether nulls are OK or not as a programming pattern, but I think it might be useful to look at this getParentFile()
method specifically.
Non-existent File in a non-existent directory
First, let's look at a case where it behaves as you would expect. Imagine your home directory at /home/user/
and it doesn't have a vegetables
directory. So obviously there is no file called carrot
in this non-existent directory.
File fileToCreate = new File("/home/user/vegetables/carrot");
This is a non-null Object (of course, because we just created it with new
), but it refers to a File which doesn't exist. So file.exists() == false
. That's fine.
file.getParentFile()
in this case is also a non-null Object, and it refers to a directory which doesn't exist (vegetables
). So file.getParentFile() != null
and file.getParentFile().exists() == false
. This is also fine, and in your example this is the directory which you want to create in order to write the new file. Because it's a real object you can call mkdir()
or mkdirs()
on it as you wish.
Finally, we can get the parent file of this object too, and we find that file.getParentFile().getParentFile() != null
, and also file.getParentFile().getParentFile().exists() == true
and file.getParentFile().getParentFile().isDirectory() == true
as well. This is our home directory.
Example where the parent file is null
Let's do the same again, but with an existing file this time, on a USB stick at E:\
. If our file is called apple.txt
, then we can do the same as above:
File file = new File("E:\\apple.txt");
file; // file != null, file.exists() == true, file.isFile() == true
file.getParentFile(); // exists() == true, isDirectory() == true, represents E:\
file.getParentFile().getParentFile(); // null
In this case it makes sense that the parent of E:\
is null, because the root directory doesn't have a parent. You could try to represent the same thing with a non-null object, if you really wanted to avoid returning nulls, but it would be a strange File object without a path.
Existing file with a null parent
This is a slightly more confusing case, where the file definitely exists, you can examine its properties, yet its parent path is still null. Imagine a file called potato.txt
which is in the current working directory when the java program is run. This doesn't have to be the user's home directory or anywhere special, as long as it is "here" as far as the java program is concerned.
File file = new File("potato.txt");
file; // file.exists() == true, file.isFile() == true
This file really is there, so you'd expect that the path is fully formed - but when you call file.getParentFile()
you still get null! This is probably what is happening in your case.
In the javadocs for getParentFile()
this is covered by the slightly mysterious qualification that it returns "null if this pathname does not name a parent directory." You might think that it must have a parent directory if it can find the file, but this is not the case. For this to work you need to first convert the relative path ("a file with this name in 'this' directory") into an absolute path (a fully qualified path to the file from the drive root or the system root). This is the meaning behind Skizo-ozᴉʞS
's comment that calling file.getAbsoluteFile()
gives you an equivalent absolute file path, and then calling .getParentFile()
will give you the expected result.
TL;DR
A File
object is quite capable of representing a directory which doesn't exist, this isn't the reason for your getting null
in your case. It's due to your original File
object having an unresolved relative path.
Upvotes: 1
Reputation: 1364
Generally, there's nothing wrong with returning null
in case when method design implies that requested object may be non-existing at the time of method's invokation (as in your example with fileB.getParentFile();
where fileB
could legally have no parent).
Also, it's fine to throw and properly handle NPE in some situations according to all java-devs bible -- Effective Java, 2nd Edition by Joshua Bloch - Item 60: "If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException."
One more option to avoid null-checks is Null Object Pattern usage. Don't return a null if you can help it, seriously. In case with collections, for example, returning Collections.emptyMap()
(or any other empty collection) is considered a good practice instead of returning null
.
For more info about avoiding-null practice you could check something like this article. Feel free to ask if my explanation seems too vague.
Upvotes: 2