How to join two Optional<String> with a delimiter in Java 8

I have two Optional strings, name1 and name2. I want to join the two such that the result is also an Optional with:

  1. If either one is non-empty, the result should be the non-empty name.
  2. If both are non-empty, I want the result to be joined with the delimiter AND.
  3. If both are empty, the result should be an empty Optional

My attempt at this:

StringBuilder sb = new StringBuilder();
name1.ifPresent(sb::append);
name2.ifPresent(s -> {
    if (sb.length() > 0) {
        sb.append(" AND ");
    }
    sb.append(s);
}
Optional<String> joinedOpt = Optional.ofNullable(Strings.emptyToNull(sb.toString()));

This works, but seems ugly and not very functional.

PS: There is a similar question but the accepted answer is wrong. Specifically, if name1 is empty and name2 is not, it returns an empty optional.

Solution:

One solution is to stream and reduce():

Optional<String> joinedOpt = Stream.of(name1, name2)
        .filter(Optional::isPresent)
        .map(Optional::get)
        .reduce((a, b) -> a + " AND " + b);

Feel free to replace the filter/map combo with Java 9 or Guava as others have suggested.

Optional in Java conditional operator leads to NullPointerException

I have a List<> of an Dto containing two parameters: type and value. Now I would like to find one element of the list with type “C” and read out the value.

When executing the following java code I get a NullPointerException which I do not understand:

class TestDto
{
    private String type;
    private Double value;

    TestDto(final String type, final Double value)
    {
        this.type = type;
        this.value = value;
    }

    public String getType() { return type; }
    public Double getValue() { return value; }
}

List<TestDto> testList = new ArrayList<>();
testList.add(new TestDto("A", 11.111d));
testList.add(new TestDto("B", 22.222d));
testList.add(new TestDto("C", null));

Predicate<TestDto> typePredicate = c-> c.getType().equals("C");
Optional optional = testList.stream().filter(typePredicate).findFirst();

if(optional.isPresent()){
    System.out.println("if-output = " + ((TestDto) optional.get()).getValue());
}

Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

System.out.println(value);

The exception appears in the following line:

Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

The value of the list element with type “C” is null, so I would expect the Double value to become null – which would be ok. This works inside of the if statement, it prints “if-output = null” as expected.

I would expect the if statement to be identical with the conditional operator. Do you have an idea why I get the NullPointerException?

Some remarks:

  • I have reduced the problem to the minimum. I do understand that there are easier ways to get the value of the Dto. I would just like to understand why the code shown above doesn’t work.

  • If you search for type “A” or “B” there is no error and the value is printed out twice

  • The replacement value “0” should be “0d” instead but it compiles with “0”. However when changing the code to:

Double value = optional.isPresent() ? null : 0;

it does not compile until I change the replacement value to “0d”. Maybe this helps to unserstand the problem.

Solution:

It’s a slightly funny one. Your ternary operator here:

optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

is using a primitive zero. Java is deciding to first unbox your null Double to a primitive double, so that both results are of the same type, and that causes a NullPointerException.

If you replace 0 with Double.valueOf(0), both results of the ternary are of the type Double and so no unboxing needs to take place.

optional.isPresent() ? ((TestDto) optional.get()) : Double.valueOf(0);

As an aside, all of the horrible casting which makes your code look so ugly in places is a result of you not using the generic version of Optional. If you use generic version, your code could look like this:

Optional<TestDto> optional = testList.stream().filter(typePredicate).findFirst();
       // ^ Generics!

if(optional.isPresent()){
    System.out.println("if-output = " + optional.get().getValue());
}

Double value = optional.isPresent() ? optional.get().getValue() : Double.valueOf(0);

System.out.println(value);