JavaDeveloper
JavaDeveloper

Reputation: 5660

Avoiding Null pointer when single value needs to be returned

Firstly, there are bunch of questions on stackoverflow on null pointers - but could not find this one. It it existed and i did not find it then please spare my mistake.

Question is generic - if a function returns just one element then how to deal with missing 'element' case. Eg: the sample code is just a sample.

public int findSmallestNumberGreaterThanX(int a[], int x) {
  // do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
     // what ??
   }
}

If there was no number in array greater than x - what to do ?

  1. Effective java mentions return empty array instead of null pointer - but is it worth creating an array if function returns single element ?

  2. Next option is return null. I have seen bunch of posts which reject the idea of returning null.

  3. Third is to return an object { boolean found; int value; } . This sounds like an overkill.

Please suggest me a best approach here.

Upvotes: 3

Views: 202

Answers (7)

Bohemian
Bohemian

Reputation: 425083

It's very common to return null for a "not found" result. Returning a "special" value, such as Integer.MIN_VALUE is OK, because mathematically that is not a legitimate result, but it would be an unconventional approach for the caller to dealt with.

You have two options:

  1. Throw an Exception if not found
  2. Change the return type to an object type and return null

Option 1. is generally not a good idea, but if you absolutely must return an int then use it

Option 2. is the more common solution, documented with javadoc

/**
 * @returns null if not found
 */
public Integer findSmallestNumberGreaterThanX(int a[], int x) {
    // do what ever logic.
    if (numFound)
        return smallesNumberGreaterThanX;
    return null;
}

Upvotes: 0

Petr
Petr

Reputation: 63379

Another solution not yet mentioned is to have a special class representing values with failures. In one of our projects we had

public interface Option<T>
    extends java.util.Collection<T>
{
    // Throws an exception if empty.
    public T get();
    // Returns `deflt` if empty.
    public T getOrElse(T deflt);
    public boolean isEmpty();
}

Option represents either a single value of type T or no value. (It implements Collection so that it can be viewed as a collection of 0 or 1 elements, which allows you to use it for example in for comprehensions, but it's probably not important for your case.) It had two subclasses, one representing an empty Option and one representing a full one:

// ---

public final class None<T>
    extends AbstractCollection<T>
    implements Option<T>
{
    public None() {}
    // ...
}

and

public final class Some<T>
    extends AbstractCollection<T>
    implements Option<T>
{
    private final T value;

    public Some(T value) {
        this.value = value;
    }

    // ...
}

Full code available here. It is just a variant of Scala's Option class.

In your case you'd use it as

public Option<Integer> findSmallestNumberGreaterThanX(int a[], int x) {
  // do what ever logic.
  if (numFound) { return new Some<Integer>(smallesNumberGreaterThanX); }
  else { return new None<Integer>(); }
}

Creating such an object has negligible overhead (unless you create millions of them), and gives a nice semantic distinction between a successful and a failed operation.

Upvotes: 2

Ali
Ali

Reputation: 58491

There is one more solution not yet mentioned:

Instead of returning the element itself, return its index. If there is no such element, either return -1 or the array size. This approach is quite common in C++ with iterators.

Upvotes: 2

Vishal K
Vishal K

Reputation: 13066

If the smallesNumberGreaterThanX doesn't include x itself then You can use something like this:

public int findSmallestNumberGreaterThanX(int a[], int x) {
  // do what ever logic.
  if (numFound) { return smallesNumberGreaterThanX; }
  else {
     return x;
   }
}

And While you call the method it could be used like this:

int var = findSmallestNumberGreaterThanX(a ,x);
if (var == x)
{
    System.out.println("No value found");
}

Upvotes: 2

Martin Wickham
Martin Wickham

Reputation: 462

I see several ways to solve this problem. I recommend using (1) or (2), and avoiding (3) and (4).

(1): throw an exception. Your method would look like:

public int findSmallestNumberGreaterThanX(int a[], int x)
    throws NoSuchNumberException {
  // do what ever logic.
  if (numFound) { return smallestNumberGreaterThanX; }
  else {
    throw new NoSuchNumberException();
   }
}

and would be called by saying

try {
  int smallestNum = findSmallestNumberGreaterThanX(a, x);
  //use smallestNum
} catch(NoSuchNumberException e) {
  //handle case where there is no smallestNum
}

You would also have to create the class NoSuchNumberException:

public class NoSuchNumberException extends Exception {

  public NoSuchNumberException() {}

  public NoSuchNumberException(String message) {
    super(message);
  }
}


(2): Slightly refactor your code.

Instead of doing everything in one method, make the method

public int findSmallestNumber(int a[]) {...}

and then say

int smallestNum = findSmallestNumber(a);
if (smallestNum > x) {
  //use smallestNum
} else {
  //handle case where there is no smallestNum > x
}


(3): Set your return type to Integer, and return null. Java will automatically cast between int and Integer, and null is a valid value for Integer. Just be sure to check for null wherever you use this method, because if you try to cast null to an int, it will break.


(4): return a number less than x. (I strongly recommend you do not use this solution unless you can also use that number somehow.) Since the number is less than x, it can be identified as an error condition.

Upvotes: 3

Eric
Eric

Reputation: 19873

It depends on what your function returns. If it returns a value, then any value is valid so return value cannot be used for validity control.

If you return the index of the value you found in the array, then anything below zero can be considered as illegal value and can be used for error code.

Maybe you can add a parameter that will contain your return value, and change your function so that it will return a boolean indicating whether the number is found or not

Upvotes: 3

sasha.sochka
sasha.sochka

Reputation: 14715

If your comparison is strict you can return Integer.MIN_VALUE as it's the only value which cannot be returned in another way. (as it's smaller than all other values except itself).

Upvotes: 3

Related Questions