5

I have a CreateOrder instance which has some String, Integer and Double states in it. When I create an object for CreateOrder in my JUnit test and send it over, I am able to validate String attributes but not Integer using Optional API as follows -

String aoid = Optional.ofNullable(createOrder.getAltorderid()).orElse("");

int quantity = Integer.parseInt(each.getQty());
double amount = Double.parseDouble(each.getPrice().getAmount());

Like for aoid, I also want to user ofNullable() for integer but not able to figure it out how. My intention behind this is to make my code safe from NullPointerExceptions and hence I want to make the user of powerful Optional for Integer and Double. I am fairly new to Java 8 and getting confused if I should use OptionalInt or Optional<Integer>? If Optional<Integer>, how to use it like I have used for String?

Naman
  • 27,789
  • 26
  • 218
  • 353
a13e
  • 838
  • 2
  • 11
  • 27

3 Answers3

2
Integer.parseInt(each.getQty())

is safe enough since if each.getQty is null, you would end up getting a NumberFormatException and that should be the behavior when you're trying to parse a String to an Integer and are not certain of it.

On the other hand still, you can default to 0 for the value being null as :

int quantity = Optional.ofNullable(each.getQty())
                       .map(Integer::parseInt)
                       .orElse(0);

similarily for amount

double amount = Optional.ofNullable(each.getPrice().getAmount())
        .map(Double::parseDouble)
        .orElse(Double.NaN);
Naman
  • 27,789
  • 26
  • 218
  • 353
  • if input is not is invalid, this is generating NumberFormatException – a13e Jan 10 '19 at 08:47
  • @AniruddhaTekade what do you expect in such cases? It should ideally be thrown. – Naman Jan 10 '19 at 08:53
  • I want to set the default values if exception occurs. The getter methods are implemented by someone else and the code is being referred by Gradle as dependencies. Since I can not change those methods, I want to make sure that if I receive invalid input, my code will set default 0/0.0/ " " for int/double/string types. – a13e Jan 10 '19 at 08:57
  • 3
    @AniruddhaTekade Well, please edit the question in that case, since the question explicitly added the requirement of making the statement null safe and current code as well doesn't handle the exception either. Also, though handling the exceptions within streams/optional APIs is possible its much chaotic in my opinion than a simple iterative approach. – Naman Jan 10 '19 at 09:02
2

Try this

Optional.ofNullable(each.getQty()).map(Integer::valueOf).orElse(0)
Hadi J
  • 16,989
  • 4
  • 36
  • 62
  • If my code gets invalid input, would the exception be thrown in here? – a13e Jan 10 '19 at 08:37
  • It isn't elegant `.map(s ->{ try { return Integer.valueOf(s); }catch (Exception e){ return 0; } })...` – Hadi J Jan 10 '19 at 08:43
  • 1
    `catch (Exception e){ return null; }` would make more sense than `catch (Exception e){ return 0; }`, as you want the optional to become absent in that case. – Holger Jan 10 '19 at 10:28
0

First of all I think you're misunderstanding the purpose of Optional.

The main point of Optional is to provide a means for a function returning a value to indicate the absence of a return value. See this discussion. This allows the caller to continue a chain of fluent method calls.

Stuart Marks, Java and OpenJDK developer

So in order to use Optional API properly you need to rethink your code. Assuming your each has nullable aoid your .getAltOrderId() method should be implemented like this:

Optional<String> getAltOrderId() {
    return Optional.ofNullable(this.aoid);
}  

Then you can use it as follows:

String aoid = createOrder.getAltOrderId().orElse("");

Please read this post for more detailed explanation.

Assuming you modified your .getQty() method to return Optional<String>, this should do what you need:

int quantity = each.getQty()
                   .map(Integer::valueOf)
                   .orElse(0);
ETO
  • 6,970
  • 1
  • 20
  • 37