3

I have been looking for a short version of the following statement in Java:

if(headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT) !=null ) {
      record
          .setNativeHeadersPresent((boolean) headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT));
    }

If I would like to use Optional.ofNullable it doesn't work as I need to cast the object to boolean as well.

P.S: I am using Java8.

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Ali
  • 1,759
  • 2
  • 32
  • 69
  • Considering `headers` as a `Map`, another way to resolve things would be `if(headers.containsKey(BinderHeaders.NATIVE_HEADERS_PRESENT)) { record.setNativeHeadersPresent((boolean) headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT)); }`. One doesn't always need an `Optional` to get rid of `null`s in the code. – Naman Aug 31 '19 at 01:59
  • You have three possible input conditions for the `NATIVE_HEADERS_PRESENT` value: `true`, `false` and `null`. Are you saying that if the value is `null` you don't want to invoke `record.setNativeHeadersPresent()` at all? Sounds like there's a logic leak there, or bad database design in that something called `NATIVE_HEADERS_PRESENT` does not sound like it should allow a `null` value. – Jim Garrison Aug 31 '19 at 03:43
  • @JimGarrison Yes. That's right. NATIVE_HEADERS_PRESENT is a message header that I received from an external party, I cannot be sure that always it is going to be provided. However, the downstream system only accepts 'true' and 'false', so I just want to say that if it doesn't exist, don't set the value as null is not accepted. – Ali Aug 31 '19 at 08:52
  • 1
    If I understand you, you want to map input {true,false,null} -> {true,false} with both input null and input false mapping to output false. Is that correct? – Jim Garrison Aug 31 '19 at 16:06

3 Answers3

3

It's not what Optional.ofNullable for, but I will share how it can be done because I love method references.

Optional.ofNullable(headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT))
        .map(boolean.class::cast)
        .ifPresent(record::setNativeHeadersPresent);

Since you've got a Map<String, String>, Map#getOrDefault could be an option.

record.setNativeHeadersPresent(
    Boolean.parseBoolean(
        headers.getOrDefault(BinderHeaders.NATIVE_HEADERS_PRESENT, "false")
    )
);
Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • Do we have any other way of addressing that in Java without using Optional, then? I am a really big fan of if you could do something it doesn't mean you should do it. – Ali Aug 31 '19 at 01:57
  • @Alin we have control flow statements which are fine in most cases. They keep things simple and to the point. – Andrew Tobilko Aug 31 '19 at 10:12
  • 2
    @Alin you may want to use [`Map#getOrDefault`](https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Map.html#getOrDefault(java.lang.Object,V)). I assume you get a String, so it would be `record.setNativeHeadersPresent(Boolean.parseBoolean(headers.getOrDefault(BinderHeaders.NATIVE_HEADERS_PRESENT, "false")));` – Andrew Tobilko Aug 31 '19 at 10:13
  • @AndrewTobilko `Map#getOrDefault()` returns the default only if the key is not present, but will return `null` if the map permits null values and a null value was associated with the key. – Jim Garrison Sep 01 '19 at 03:52
  • Why does your second example suddenly assume that the map values are strings? Further mind the difference between calling `setNativeHeadersPresent` when the value is present and always calling `setNativeHeadersPresent`… By the way, it must be `Boolean.class::cast` instead of `boolean.class::cast`, as you can not cast an object to a primitive type. – Holger Sep 02 '19 at 09:35
2

You seem to be trying to implement this mapping

Input  ->  Output
-----      ------
true       true
false      false
null       false

If you MUST use Optional, the most succinct way of expressing this is

Optional.ofNullable(headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT)).orElse(false);

However, you don't need Optional at all. The following will do what you are asking for:

Boolean nhp = headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT);
record.setNativeHeadersPresent((nhp == null) ? false : nhp);

If you want it in one statement (at the expense of invoking headers.get() twice):

record.setNativeHeadersPresent(
    (headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT) == null) 
        ? false 
        : headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT));

Important Note: The use of Map#getOrDefault(...,false) may not work. If the Map implementation supports null values, then getOrDefault() can still return null if a null value was associated with that key. (i.e. at some point put(key,value) with value==null was executed). The default value is returned only if the key was not present in the map.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
  • I appreciate your approach using a conditional expression. With all the fuss about functional programming in Java, ppl. tend to miss that a conditional expression **is** the functional equivalent of if-else :) – Stephan Herrmann Aug 31 '19 at 19:04
  • Thanks for your answer. The only thing is the Map is a type of and I need to cast it to boolean as well. – Ali Sep 01 '19 at 00:50
  • 1
    @Alin If you really cannot narrow down the value type beyond just `Object` then you also need to handle the case where the value cannot be converted to `boolean`. I presume you want `false` then. Other than that this approach still works, you just have to test for type compatibility as well as `null`. – Jim Garrison Sep 01 '19 at 03:55
  • @StephanHerrmann still, any compound boolean expression containing a `boolean` literal can be expressed without. So instead of `(nhp == null) ? false : nhp`, you can simply use `nhp != null && nhp`. – Holger Sep 02 '19 at 09:39
  • @Alin then, simplest solution: `record.setNativeHeadersPresent(Boolean.TRUE.equals(headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT)));` – Holger Sep 02 '19 at 09:40
0

If I understand correctly, a simple call to ifPresent should work:

Optional.ofNullable(headers.get(BinderHeaders.NATIVE_HEADERS_PRESENT))
    .ifPresent(
        x -> record.setNativeHeadersPresent((boolean)x)
    )

It doesn't matter what you do with the optional (whether you cast it or not), because ifPresent accepts a "function" as its parameter. You can pass in code that does whatever you like.

Sweeper
  • 213,210
  • 22
  • 193
  • 313