1

I'm writing a program which needs to handle objects with many wrapped number variables such as Long, Double, Integer etc. How can I safely perform numeric operations on these without having to put null-checks everywhere?

I expect this is something that pretty much every Java programmer must deal with sooner or later, so I'm quite surprised that there aren't hundreds of blog posts and SO questions on the topic.

My current solution is to filter all the numbers trough a method like this:

private static safelyUnbox(Integer i) {
    return i == null ? 0 : i.intValue();
}
...
sumVariable += safelyUnbox(stupidObject.getNumberOfWhatever());
JohnEye
  • 6,436
  • 4
  • 41
  • 67
  • 1
    Why do you need null checks? – Boann Feb 13 '15 at 14:03
  • 5
    Also, why is it safer to return `0` than throw a NPE? If the collection is supposed to have no null values, that kind of contraption will hide your actual bugs. Getting a NPE error is way better than giving the user an answer that only **seems** to be valid. – SJuan76 Feb 13 '15 at 14:05
  • Why can you not use primitives? – barq Feb 13 '15 at 14:05
  • @Boann: To avoid nullPointerExceptions when adding up numbers. They are optional, so they are quite often `null`. – JohnEye Feb 13 '15 at 14:05
  • Document that the getNumberOfWhatever() never returns null, or use null value objects, or guava's optional component. – Cativail Feb 13 '15 at 14:07
  • 1
    @barq: Because the values are optional and can be null. I cannot change the object in question unfortunately. – JohnEye Feb 13 '15 at 14:08
  • Have you considered wrapping the object? If you have a HashMap, but what you really want is a Counter (I believe this is the most common case of your predicament), you can create a wrapper for it whose get method calls the underlying get method and checks for null – dspyz Feb 13 '15 at 15:30
  • In general, null and 0 are not the same thing and there's no reason you would want to implicitly cast between them. That's just asking for C++-style bugs. Maybe a little more detail about your use-case is in order. – dspyz Feb 13 '15 at 15:34
  • @dspyz: OK, let's get a bit deeper. I have quite a large object with many variables holding all sorts of data, mostly numbers, which may or may not be there (it's actually a representation of a processed XML document). I want to pick a bunch of variables out of it, do a little bit of adding or subtracting and present them to the user. I want to avoid having to write `if (numberOfThings != null) { total += numberOfThings; }` every single time I do a simple sum. – JohnEye Feb 13 '15 at 23:52
  • Yeah, so just write a function to wrap whatever function you use to return number_of_things so that it returns 0 instead of null. – dspyz Feb 13 '15 at 23:58

3 Answers3

5

Java 8 provides a good alternative to checking against null. If an Integer (for example) might or might not have a value then you can declare it as Optional<Integer>. The Optional class has plenty of useful utilities for returning default values, throwing exceptions, checking if the value is present etc.

The advantage of declaring Optional<Integer> is that you are making completely clear to the reader that 'no value' is a legitimate state. Anyone maintaining your code has no choice but to use the Optional methods to decide what happens if the value is present or absent.

If, on the other hand, the argument is mandatory then the simplest option is to just assert that it is not null before using it.

The great advantage (in my view) of using Optional whenever a value might not be present is that you can start relying in your code on the assumption that null is always an error.

Optional even provides a neat way of converting a potentially null variable to an Optional (for example, if it's passed to you and you have no control over its value on entry to your code). It works like this:

Optional<Integer> optVal = Optional.ofNullable(val);

You can then use the new variable in the same way as any other Optional. For example:

optVal.ifPresent(myList::add);

Or:

return optVal.orElse(27);
sprinter
  • 27,148
  • 6
  • 47
  • 78
  • This is what I would probably use if I could, but I cannot change the object which contains the nullable variables and I cannot use Java 8. Still a good answer though. – JohnEye Feb 13 '15 at 14:10
  • Ok I'll add a comment on how you can still use Optional. – sprinter Feb 13 '15 at 14:11
  • Using Optional doesn't make the code in this case any shorter or simpler than doing null checks. – Boann Feb 13 '15 at 14:14
  • @Boann `sumVariable += Optional.ofNullable(stupidObject.getNumberOfWhatever()).orElse(0);` seems at least simpler to me, maybe not shorter... – glglgl Feb 13 '15 at 14:15
  • 1
    @Boann no but it makes it clearer and safer. If you use `Integer` the reader does not know if it should be allowed to be null. If you use `Optional` it's perfectly clear. – sprinter Feb 13 '15 at 14:16
2

You have a very specific issue and are trying to generalize it without thinking about it.

  • It could a precondition that null values are not valid. In your case, you state in your comments that it is not. But if it were, you should handle that instead of hidding it.

  • The "safe" value may differ. You chose 0 because you are adding up the numbers, what if you were multiplying (or using it as a quotient)? This is a knowledge your safelyUnbox method does not have.

Avoid generalizing everything. For your case, the best code is as simple as:

for(Integer integ : myCollection) {
  if (integ != null) {
    sum += integ;
  }
}

Every other situation will have its own, most appropiate solution. Compare that with

for(Integer integ : myCollection) {
  sum += safeUnboxThatDefaultsto0(integ);
}

or

for(Integer integ : myCollection) {
  sum += safeUnbox(integ, 0);
}

What are you winning by using the method?

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • 1
    Note: Solutions based in delegates/lambda calculus (like sprinter's) are also good because they give a more semantic way of doing the same. – SJuan76 Feb 13 '15 at 14:22
  • What I want to avoid is writing null checks everywhere - they bloat the code quite a bit. What I expected someone to answer was something like "hey, there's an Apache Commons method for that" :-) – JohnEye Feb 13 '15 at 20:14
1

You can use Google's Guava Library Using and avoiding null

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

The biggest advantage of Optional isn't in readability: the advantage is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case. Null makes it disturbingly easy to simply forget things .

Suppose this case :

String meterReading=getValueFromRemoteSite();
System.out.println(meterReading.toLowerCase()); //Chances for NPE

but using Optional scenario is diffrent

Optional meterReading = Optional.of(getValueFromRemoteSite(););
if( meterReading.isPresent() )
{
   System.out.println( meterReading.get() );
}  
Neeraj Jain
  • 7,643
  • 6
  • 34
  • 62
  • What is the advantage of Guava's `Optional` over that of Java 8, apart from the missing `Set asSet()` method? – glglgl Feb 13 '15 at 14:14
  • 2
    @glglgl Java 8's Optional is inspired from Guava's Optional. If you cannot use Java 8, Guava's Optional is a good solution. – Arnaud Denoyelle Feb 13 '15 at 14:15
  • Guava's `Optional` was such a good idea that it's been added to Java 8. There's really no reason to use Guava's now. In fact for consistency with `Stream` methods that return `Optional` it's best to use the Java 8 one. – sprinter Feb 13 '15 at 14:18
  • @sprinter That's not true. If you have to work with MATLAB R2012a and want it to use Java classes, these Java classes must be made compliant to Java 1.6... It is an aspect which I completely overlooked when asking about the advantage... – glglgl Feb 13 '15 at 14:19
  • @glglgl Yes that's a good point. Fortunately I can work in pure Java 8 so I don't come across that problem but I see your point that Guava's backward compatibility is an advantage is some circumstances. – sprinter Feb 13 '15 at 14:22
  • @glglgl , The biggest advantage for you is that it is currently life savior for you (as it is the only best option left as you can not use Java 8 :-) ) Still hope this answers explains the your [doubt](http://stackoverflow.com/questions/18681243/should-i-use-java8-guava-optional-for-every-method-that-may-return-null) – Neeraj Jain Feb 13 '15 at 14:34
  • I don't see how this is different from checking for `null` explicitly, you still have to call `isPresent()`. – JohnEye Feb 13 '15 at 20:11