StackOverflow has a good discussion about this exact topic in this Q&A. In the top rated question, kronoz notes:

Returning null is usually the best idea if you intend to indicate that no data is available.

An empty object implies data has been returned, whereas returning null clearly indicates that nothing has been returned.

Additionally, returning a null will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code - attempting to access a member of nothing makes no sense. Accessing members of an empty object will not fail meaning bugs can go undiscovered.

Personally, I like to return empty strings for functions that return strings to minimize the amount of error handling that needs to be put in place. However, you'll need to make sure that the group that your working with will follow the same convention - otherwise the benefits of this decision won't be achieved.

However, as the poster in the SO answer noted, nulls should probably be returned if an object is expected so that there is no doubt about whether data is being returned.

In the end, there's no single best way of doing things. Building a team consensus will ultimately drive your team's best practices.

Answer from JW8 on Stack Exchange
🌐
Coderanch
coderanch.com › t › 99773 › engineering › Null-Empty-object-Return-Type
Null or Empty object (Return Type) (OO, Patterns, UML and Refactoring forum at Coderanch)
For insance if doSomething is responsible for getting all the transactions for a given customer account. A null String array return value may mean that the specified account doesn't exist, while an empty (but non-null) array would mean the account does exist, but there have been no transactions yet.
Top answer
1 of 16
102

StackOverflow has a good discussion about this exact topic in this Q&A. In the top rated question, kronoz notes:

Returning null is usually the best idea if you intend to indicate that no data is available.

An empty object implies data has been returned, whereas returning null clearly indicates that nothing has been returned.

Additionally, returning a null will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code - attempting to access a member of nothing makes no sense. Accessing members of an empty object will not fail meaning bugs can go undiscovered.

Personally, I like to return empty strings for functions that return strings to minimize the amount of error handling that needs to be put in place. However, you'll need to make sure that the group that your working with will follow the same convention - otherwise the benefits of this decision won't be achieved.

However, as the poster in the SO answer noted, nulls should probably be returned if an object is expected so that there is no doubt about whether data is being returned.

In the end, there's no single best way of doing things. Building a team consensus will ultimately drive your team's best practices.

2 of 16
101

In all the code I write, I avoid returning null from a function. I read that in Clean Code.

The problem with using null is that the person using the interface doesn't know if null is a possible outcome, and whether they have to check for it, because there's no not null reference type.

In F# you can return an option type, which can be some(Person) or none, so it's obvious to the caller that they have to check.

The analogous C# (anti-)pattern is the Try... method:

public bool TryFindPerson(int personId, out Person result);

Now I know people have said they hate the Try... pattern because having an output parameter breaks the ideas of a pure function, but it's really no different than:

class FindResult<T>
{
   public FindResult(bool found, T result)
   {
       this.Found = found;
       this.Result = result;
   }

   public bool Found { get; private set; }
   // Only valid if Found is true
   public T Result { get; private set;
}

public FindResult<Person> FindPerson(int personId);

...and to be honest you can assume that every .NET programmer knows about the Try... pattern because it's used internally by the .NET framework. That means they don't have to read the documentation to understand what it does, which is more important to me than sticking to some purist's view of functions (understanding that result is an out parameter, not a ref parameter).

So I'd go with TryFindPerson because you seem to indicate it's perfectly normal to be unable to find it.

If, on the other hand, there's no logical reason that the caller would ever provide a personId that didn't exist, I would probably do this:

public Person GetPerson(int personId);

...and then I'd throw an exception if it was invalid. The Get... prefix implies that the caller knows it should succeed.

🌐
Javapractices
javapractices.com › topic › TopicAction.do
Java Practices->Prefer empty items to null ones
Here's an example of using an empty, zero-length array instead of a null reference. This simplifies the caller, since they never have to check for null values. (An even better alternative is to use replace the array with a possibly-empty collection.) import java.util.*; public final class StockPortfolio { //..elided /** A field is implemented internally as a List, but offered to the user of this class as an Array.
Top answer
1 of 2
3

A solution such as Option<T> is not a so bad idea. In fact, it has been successfully introduced in Haskell as a Maybe (but I don't know if this is the first time this solution has been used). Maybe monads are common in Haskell programs. Since, other languages have adopted the same system. For instance, Scala has an Option type.

If you don't want to become dependent of Guava, you could use Java 8, which introduces the Optional class.

However, Option/Maybe/… types are more relevant in a functional environment, because what you typically want to do is to get a behaviour/a property from the element if it really exists, and to get nothing or a default behaviour/property otherwise. So, a typical use of Options consists in

  • applying a function A->B on the Option[A] in order to get an Option[B];
  • switching your code on the basis of the real content of the Option (for instance, by using Pattern matching if the language supports it and if Option has two subtypes, or by using method overload);
  • or filtering the Options that represent (non-)existing elements.

As an alternative, you could use the Null Object Pattern, in which you have an abstract class MyClass and two concrete subclasses: MyRealClass and MyNullClass. You manipulate instances of MyClass, but generate instances of MyRealClass (if the element is really existing) or MyNullClass (if the element doesn't exist). MyNullClass contains the default behaviours/properties. If the null objects are stateless (which is typically the case), one could cache them, or even make them singletons.

This pattern is described in [Fowler].

[Fowler] Martin Fowler, Kent Beck, Refactoring: Improving the Design of Existing Code.

2 of 2
2

The whole point of a value object is that equality isn't based on identity; you could very well have two distinct blank objects. In fact, whether all blank objects are the same or different objects should be an implementation detail. For those reasons, the second approach is not good. If you look at the Java 8 APIs, there's a notion of a "value-based class" with the following properties:

  • are final and immutable (though may contain references to mutable objects);
  • have implementations of equals, hashCode, and toString which are computed solely from the instance's state and not from its identity or the state of any other object or variable;
  • make no use of identity-sensitive operations such as reference equality (==) between instances, identity hash code of instances, or synchronization on an instances's intrinsic lock;
  • are considered equal solely based on equals(), not based on reference equality (==);
  • do not have accessible constructors, but are instead instantiated through factory methods which make no committment as to the identity of returned instances;
  • are freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior.

The documentation further adds:

A program may produce unpredictable results if it attempts to distinguish two references to equal values of a value-based class, whether directly via reference equality or indirectly via an appeal to synchronization, identity hashing, serialization, or any other identity-sensitive mechanism. Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided.

There's no way to disable the == operator in Java so that warning is the best you can do.

Thus, your first approach is correct, with the caveat that foo1.equals(foo2) should always be true when foo1.isBlank() and foo2.isBlank() even if foo1 != foo2.

Top answer
1 of 3
1

There is a way to initialize the destination object in Dozer.

  1. Define a factory class for the destination Object.
  2. Specify the create-method for the destination object as the method in the above factory class.

Take your example, I presume you want to map Person to PersonVO and Address to AddressVO.

Create a factory class for PersonVO

public abstract class PersonVOFactory {
    private PersonVOFactory() {
    }
    public static PersonVO createPersonVO() {
        PersonVO personVO = new PersonVO();
        personVO.setAddressVO(new AddressVO());
        return personVO;
    }
}

Specify the above create method for Person to PersonVO mapping.

<mapping map-id="person-mapping">
    <class-a>Person</class-a>
    <class-b create-method="PersonVOFactory.createPersonVO">PersonVO</class-b>
    <field>
        <a>address.addressField1</a>
        <b>addressVO.addressField1</b>
    </field>
    <field>
        <a>address.addressField2</a>
        <b>addressVO.addressField2</b>
    </field>
</mapping>

Now the statement, personvo.getAddressVO.getAddressField1() will not throw an NPE.

2 of 3
0

If you can modify the setter method of the PersonVO class, you could do as follow :

public void setAddressVO(AddressVO address) {
    this.addressVO = address == null ? new AddressVO() : address;
}

Thus you will be sure that the field addressVO is never null.

Please note that this is rather dirty because :

  1. if a person has no address, his address field should be null rather than an empty AddressVO object.
  2. a customized setter like this is a bad practice as most users of your class would expect the set method to set the value and do nothing more. You can optionally create a new method initAddressVO and call this method from dozer using the set-method attribute in the configuration file.

It would be much better (if it's possible) to check if address is null with some if to avoid the NullPointerException.

🌐
Javapractices
javapractices.com › topic › TopicAction.do
Java Practices->Return Optional not null
*/ public String getAddress() { return address; } /** Might be an empty Set. */ public Set<Human> getFriends() { //make sure the caller can't modify the private Set return Collections.unmodifiableSet(friends); } /** May or may not be present. The returned Optional object is itself never null! That would completely defeat the purpose of using {@code Optional<T>}. */ public Optional<LocalDate> getBirthDate() { return Optional.ofNullable(birthDate); } /** Debugging only.
🌐
Coderanch
coderanch.com › t › 411008 › java › Differerce-NULL-Empty-object
Differerce : NULL and Empty object? (Beginning Java forum at Coderanch)
Think of it like this: You could have a bucket(object) in your hand or not. No bucket = null. If you do have a bucket, does it have anything in it? Nothing in it = empty. ... It's not NULL, it's null. At least in Java. NULL is permissible in SQL. In Java, null is described as a state of non-existence.
Find elsewhere
🌐
DZone
dzone.com › coding › languages › null object pattern in java
Null Object Pattern in Java
August 22, 2018 - There are several static APIs to creating Optional objects: Optional.empty() : To create an empty Optional object, use the empty API: @Test public void optionalEmptyTest() { Optional<Shape> empty = Optional.empty(); assertFalse(empty.isPresent()); ...
🌐
Reddit
reddit.com › r/askprogramming › should i return null or an empty object?
r/AskProgramming on Reddit: Should I return null or an empty object?
July 25, 2023 -

My company uses files that are essentially merged XML files into one. I wrote a pretty basic parser and node object that contains the tag name, text, and child node objects. Recently I ran into an error where the file couldn't be found, and my function that searches for child nodes returned null (as it should). But it caused a runtime error, so I'm trying to figure out the best way to address issue. Should I return an empty object so that the code doesn't crash, or should I continue returning null and wrap it in a try/catch?

Top answer
1 of 16
206

Returning null is usually the best idea if you intend to indicate that no data is available.

An empty object implies data has been returned, whereas returning null clearly indicates that nothing has been returned.

Additionally, returning a null will result in a null exception if you attempt to access members in the object, which can be useful for highlighting buggy code - attempting to access a member of nothing makes no sense. Accessing members of an empty object will not fail meaning bugs can go undiscovered.

2 of 16
44

It depends on what makes the most sense for your case.

Does it make sense to return null, e.g. "no such user exists"?

Or does it make sense to create a default user? This makes the most sense when you can safely assume that if a user DOESN'T exist, the calling code intends for one to exist when they ask for it.

Or does it make sense to throw an exception (a la "FileNotFound") if the calling code is demanding a user with an invalid ID?

However - from a separation of concerns/SRP standpoint, the first two are more correct. And technically the first is the most correct (but only by a hair) - GetUserById should only be responsible for one thing - getting the user. Handling its own "user does not exist" case by returning something else could be a violation of SRP. Separating into a different check - bool DoesUserExist(id) would be appropriate if you do choose to throw an exception.

Based on extensive comments below: if this is an API-level design question, this method could be analogous to "OpenFile" or "ReadEntireFile". We are "opening" a user from some repository and hydrating the object from the resultant data. An exception could be appropriate in this case. It might not be, but it could be.

All approaches are acceptable - it just depends, based on the larger context of the API/application.

🌐
Baeldung
baeldung.com › home › java › java string › difference between null and empty string in java
Difference Between null and Empty String in Java | Baeldung
April 19, 2024 - If we assign null to a String object, ... no value or reference. An empty String is a valid String object having no characters, and as a result, all the String operations are available on this object....
Top answer
1 of 6
17

MattPutnam's answer is right on point, and I second it. I'd add this: the concept of "null object," when you analyze it, seems to boil down to the mathematical concept of a monoid. You can think of it this way: a monoid is a type that has both of these things:

  1. An "append," "sum" or similar operation, which needs to be associative: a.op(b).op(c) is the same as a.op(b.op(c)).
  2. An "empty," "zero" or "null" value, that acts as the neutral element or identity element of the operation.

The classic example of the null object pattern is to return an empty list or array instead of null. Well, lists are a monoid, with append as the operation and the empty list as the neutral element.

Now, the problem that you face in your Car example is that Car isn't really a monoid; there is no notion of "the empty car" or "the neutral car", and there isn't really a sensible operation that you could use to combine two Cars into one.

So the recommendation you're rightly getting is to use something like the Java 8 Optional. And the trick is that no matter what type T is, Optional<T> is a monoid:

  1. The monoid's "combine" operation is "pick the first value if it's not empty, otherwise pick the second value":
    • x || empty = x
    • empty || x = x
  2. The neutral element is Optional.empty(), because Optional.empty().orElse(anything) is the same as just anything.

So basically, Optional<T> is a wrapper that adds a null object to types like Car that don't have one. The Optional<T>.orElse(T value) method that is a slightly refactored version of the "pick first non-empty value" monoid.

2 of 6
12

The null object pattern only makes sense when there's a reasonable, functional value for the null object to be. The purpose isn't to defer null, as you've described, but to completely eliminate the idea of null by representing the nothingness or emptiness with an actual piece of data that is still functional. For example, the natural case of holes in a tree structure, as described in the Wikipedia article.

A null car doesn't make sense. In this case, it seems like the more appropriate thing would be for getCar() to return Optional<Car>.

Top answer
1 of 3
13

Method overloading can make your implementations more efficient and cleaner:

public static boolean isEmpty(Collection obj) {
    return obj == null || obj.isEmpty();
}

public static boolean isEmpty(String string) {
    return string == null || string.trim().isEmpty();
}

public static boolean isEmpty(Object obj) {
    return obj == null || obj.toString().trim().isEmpty();
}

The Collection version is as efficient as possible.

The String version would be more efficient without the trimming. It would be best to trim your strings as soon you see them, long before they reach this call. If you can review the callers and make sure that the strings are always trimmed at their origins, then you can remove .trim() for best performance.

The Object version can be inefficient, depending on the toString implementation of the objects that will be passed to it, and because of the trimming.

I removed the comparison with null from there, because it seems pointless to me. I mean, a class whose toString method says "null" would seem very very odd.

In any case, you don't really want the Object version to be called, at all. Most importantly because it probably won't even work. Take for example an empty Map. Its toString method returns the string {}, which won't match your conditions of emptiness. (For this type you should definitely add isEmpty(Map<?, ?> map) to benefit from its isEmpty method.)

If performance is so critical, then add more overloaded implementations for all other types that you care about, for example:

public static boolean isEmpty(Something obj) {
    return obj == null || obj.isEmpty();
}

Finally, especially when something is so important, you definitely want to unit test it, for example:

@Test
public void testEmptyObject() {
    assertTrue(isEmpty((Object) null));
    assertFalse(isEmpty(new Object()));
}

@Test
public void testEmptyString() {
    assertFalse(isEmpty("hello"));
    assertTrue(isEmpty(""));
    assertTrue(isEmpty(" "));
    assertTrue(isEmpty((Object) null));
}

@Test
public void testEmptySet() {
    assertFalse(isEmpty(new HashSet<String>(Arrays.asList("hello"))));
    assertTrue(isEmpty(new HashSet<String>()));
}

@Test
public void testEmptyMap() {
    Map<String, String> map = new HashMap<String, String>();
    assertTrue(isEmpty(map));
    map.put("hello", "hi");
    assertFalse(isEmpty(map));
}
2 of 3
9

Don't.

I mean. Don't use the same method for all kinds of objects.

This method does not make much sense to me.

This line smells. A lot.

if (obj instanceof Collection)
    return ((Collection<?>) obj).size() == 0;

Beware of instanceof operator.

I am sure that whatever it is that you are trying to do here, there are better ways to do it.

Java is a statically typed language, use the static types whenever possible. If you really don't know what type the object have, then I will provide another alternative below.


// is below line expensive?
final String s = String.valueOf(obj).trim();

That depends, on the implementation of the object's toString method.

The implementation of String.valueOf is:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

return s.length() == 0 || s.equalsIgnoreCase("null");

You have already checked for obj == null. The string will only be null when the object's toString method makes it so. And instead of s.length() == 0 you can use s.isEmpty() directly. (Although that is implemented as string length == 0


Do it differently

If possible, have the types of objects you're investigating implement an interface that provides an isEmpty method and let the object decide for itself if it is empty or not.

If that is not possible, you can use a dynamically created map with ways to determine whether or not the object is "empty".

Map<Class<?>, EmptyChecker> map = new HashMap<>();
map.put(String.class, new StringEmptyChecker());
map.put(Point.class, new PointEmptyChecker());

This is a kind of Strategy pattern.

Then to determine if an object is empty:

EmptyChecker checker = map.get(obj.getClass());
checker.isEmpty(obj);

The whole thing is kinda weird though, I can't really see a particular use-case for this kind of method.

🌐
Baeldung
baeldung.com › home › java › avoid check for null statement in java
Avoid Check for Null Statement in Java | Baeldung
April 8, 2019 - Without flatMap, the result would be Optional<Optional<String>>. The flatMap operation is only performed when the Optional is not empty. Lombok is a great library that reduces the amount of boilerplate code in our projects. It comes with a set of annotations that take the place of common parts of code we often write ourselves in Java applications, such as getters, setters and toString(), to name a few. Another of its annotations is @NonNull. So, if a project already uses Lombok to eliminate boilerplate code, @NonNull can replace the need for null checks.