Reputation: 393
I am new to Java, and still learning Optionals. I understood its used to avoid Null Pointer Exception.
I have a piece of code wherein I want to use optional, which is like this:
final MetadataExtractor<FCAddress> metadataExtractor = t -> {
final Map<String, String> metadata = new HashMap<>();
metadata.put("senderCountryCode", t.getCountryCode());
metadata.put("senderState", t.getState());
metadata.put("senderPostalCode",t.getPostalCode());
return metadata;
};
Here, my use case is, if the SenderState is empty, i.e. t.getState() is empty, I want the map field to to be empty, that is not populated.
I tried something like this:
final MetadataExtractor<FCAddress> metadataExtractor = t -> {
final Map<String, String> metadata = new HashMap<>();
metadata.put("senderCountryCode", t.getCountryCode());
Optional<String> senderState = Optional.of(t.getState());
senderState.ifPresent(metadata.put("senderState", t.getState());
metadata.put("senderPostalCode",t.getPostalCode());
return metadata;
};
But this gives a compilation error, where am I going wrong in this? Error is: "ifPresent (java.util.function.Consumer) in Optional cannot be applied"
Upvotes: 2
Views: 2481
Reputation: 140457
still learning Optionals. I understood its used to avoid Null Pointer Exception.
Not necessarily. They are rather a mean that allows you to have something that represents "nothing".
Regarding your actual compile error:
senderState.ifPresent(metadata.put("senderState", t.getState());
ifPresent()
wants a consumer. From the javadoc:
public void ifPresent(Consumer<? super T> consumer)
If a value is present, invoke the specified consumer with the value, otherwise do nothing.
metadata.put() isn't a consumer. That is an ordinary method call on that map! And it will return a the "value" type of your map, so a String. Strings aren't Consumers!
Long story short: if you really want to use ifPresent()
here, then you would probably want to pass a lambda expression (see here for some examples).
In your case,
senderState.ifPresent(state -> metadata.put("senderState", state));
should do.
Upvotes: 2
Reputation: 95
You need to pass a Consumer (a lambda) to ifPresent:
senderState.ifPresent(state -> metadata.put("state", state);
// important: the Consumer always receive a parameter.
// An empty value `() ->` is not valid!
The lambda will only get executed in case senderState is present (that means, is not null).
BTW it's very important to construct your senderState
by using Optional.ofNullable(...)
! Otherwise, it'll throw an NPE.
Check out an in-depth tutorial: https://www.baeldung.com/java-optional
Upvotes: 3
Reputation: 140318
Just to present a totally different approach to the problem:
Put everything into the map, and then remove the null values after:
metadata.values().removeIf(Objects::isNull);
This is a lot neater syntactically, but may or may not be faster because of doing something and then undoing it, as opposed to just not doing it in the first place.
Upvotes: 2
Reputation: 26926
In this particular code the use of Optional
is not useful because you don't like to add an Optional
to the map, but only skip null
values.
The simplest solution that doesn't create new objects is adding a check on value of t.getState()
as follow:
final MetadataExtractor<FCAddress> metadataExtractor = t -> {
final Map<String, String> metadata = new HashMap<>();
metadata.put("senderCountryCode", t.getCountryCode());
if (t.getState() != null) {
metadata.put("senderState", t.getState());
}
metadata.put("senderPostalCode",t.getPostalCode());
return metadata;
};
Just for studying purpose the solution of GhostCat works with an Optional
:
senderState.ifPresent(() -> metadata.put("senderState", t.getState());
the complete example will be:
final MetadataExtractor<FCAddress> metadataExtractor = t -> {
final Map<String, String> metadata = new HashMap<>();
metadata.put("senderCountryCode", t.getCountryCode());
// Here you create a not useful object that can be replaced with a simple if
Optional<String> senderState = Optional.ofNullable(t.getState());
// Here you create a second not necessary object because a lambda
// espression is an instance of an anonimous class implementing
// the corresponding interface
senderState.ifPresent(() ->
metadata.put("senderState", t.getState()
);
metadata.put("senderPostalCode",t.getPostalCode());
return metadata;
};
Note that this solution will create two unnecessary objects:
Optional
senderState
Consumer
created as lambda expression inside the ifPresent
methodUpvotes: 2