Imagine an Optional.ofNullable check assigning to a String:
String result = Optional.ofNullable(class1)
.map(Class1::getClass2)
.map(Class2::getResult);
Where getResult returns a String.
While I know this doesn't compile, I can fix it by either adding toString() or .orElse(""); to sort that.
As it stands, the error is:
Bad return type in method reference, cannot convert java.lang.String
to U
I understand adding orElse("") as that will assign result to an empty String.
But what's the benefit of adding toString() if something is null along the way? Or is that just to purely get it to compile?
The return type of map is Optional <U>, so to get a real value you should call for orElse with the return type of T.
This is the toString implementation if the Optional:
#Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
So, calling toString you'll never get the real value, but a value wrapped to Optional, while orElse will return you the default provided value.
Let's see the difference:
Integer i = 4;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.toString();
System.out.println(s);
Output:
Optional[4]
With null:
Integer i = null;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.toString();
System.out.println(s);
Output:
Optional.empty
While using orElse:
Integer i = null;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.orElse("None");
System.out.println(s);
Output:
None
So you can see that there are different purposes of these methods.
And the answer to your comment:
"Is there a way to call get() and also call orElse() in the same chain?"
Integer i = 10;
String s = Optional.ofNullable(i)
.map(Objects::toString)
.orElse("None");
System.out.println(s);
Output:
10
You don't need to call get explicitly, the value will be fetched if not null;
/**
* If a value is present, returns the value, otherwise returns
* {#code other}.
*
* #param other the value to be returned, if no value is present.
* May be {#code null}.
* #return the value, if present, otherwise {#code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}
I understand adding orElse("") as that will assign result to an empty
String.
It doesn't sound like you do understand it to me because that's not a good description of what's happening. Optional.orElse does the following: if the optional contains a value, return that value. If it doesn't contain a value, return whatever argument you've given it.
It's semantically equivalent to the following:
if (optional.ifPresent())
{
return optional.get();
}
else
{
return theArgument;
}
Calling toString, while it will satisfy the compiler, is not what you want to do. You are converting the Optional object itself to a String, not getting the String from inside! While your string will be included, this is only because of how the JDK developers have decided to implement toString. They could equally have not provided an implementation, leaving you with just the default behaviour.
Calling toString on an Optional should basically never be relied upon outside of logging. It's essentially just debugging information. If you do this, then information about the Optional wrapper will be printed as well, which is almost certainly not what you want.
System.out.println(Optional.empty()); // Optional.empty
System.out.println(Optional.of("foo")); // Optional[foo]
If you want result to be null if something along the way returns null then do orElse(null)
String result = Optional.ofNullable(class1)
.map(Class1::getClass2)
.map(Class2::getResult).orElse(null);
Related
I would like to know how I can use findAny() in a data stream when it does not find any coincidence, it does not return null.
String CountryFinal= "Spain";
List<ParContriesTO> listContries = new ArrayList<SelectItem>();
listContries.add(new SelectItem(215, "Germany"));
Integer idCountry = (int) listContries.stream()
.filter(country -> country.getNoCountry().equals(CountryFinal))
.findAny().orElse(null).getCoCountry();
The Stream::findAny returns Optional and its method Optional::findAny, according to the documentation, there are 4 ways to return T:
Optional::get returns the T or throws NoSuchElementException
Optional::orElse returns T or a default value
Optional::orElseGet returns T or a value provided with Supplier
Optional::orElseThrow returns T or throws a custom exception
As far as I understand, you are looking for the second or third method which returns a defined value in case the origin is null. You can return a null-object using the Null-Object pattern which represents an object which is valid but does "nothing". Or else you can use null.
I suggest you receive a country before you let return null or anything alse and use getCoCountry() method on it (I suppose Country::getCoCountry returns either int or Integer) - otherwise, what have you done would return NullPointerException.
Try the following snippet:
Integer idCountry = listContries.stream() // Stream
.filter(c -> countryFinal.equals(c.getNoCountry())) // Get one equals to "Spain"
.findFirst() // Get Optional<Country>
.map(Country::getCoCountry) // If exists, get its code
.orElse(0); // Or else return an invalid code
Note there is no need to both filter by the country name and then check the equality since you expect there is only one "Spain".
The approach to invoke getCoCountry as last is generally bad.
What you could do is:
listContries.stream()
.filter(country -> country.getNoCountry()
.equals(CountryFinal))
.findAny().map(Country::getCoCountry).orElse(WHATEVER_YOU_WANT);
To clarify: findAny returns Optional that may contain an instance of country. You can safely invoke getCoCountry in map. This is the importance of Optional type. At this step, you're still safe since you still have an Optional that MAY contain an Integer result. In the end, you can use orElse to decide what you want to have if instance is null.
This is a code segment from another StackOverflow question:
#Override
public String convertToDatabaseColumn(final UUID entityValue) {
return ofNullable(entityValue).map(entityUuid -> entityUuid.toString()).orElse(null);
}
I am really struggling to understand the use of the Optional class. Is the return code saying "return the value of the map (a String) or NULL if that fails?
How can return be acting on a method rather than a Class - that is Optional.ofNullable()?
This is a really bad use of Optional. In fact the java developers themself say that optional should not be used in such cases, but only as a return argument from a method. More can be read in this great answer: Is it good practice to use optional as an attribute in a class
The code can be rewritten to this:
#Override
public String convertToDatabaseColumn(final UUID entityValue) {
return entityValue == null ? null : entityValue.toString();
}
Is the return code saying "return the value of the map (a String) or NULL if that fails?
Yes. You can check the documentation of Optional here. It tells you exactly what map and orElse do.
How can return be acting on a method rather than a Class - that is Optional.ofNullable()?
You are not returning the method. You are returning the return value of a method. Look at this simple example:
int myMethod() {
return foo();
}
int foo() { return 10; }
See? I am not returning foo the method, I am returning 10, the return value of foo.
Note that it is possible to return methods, with functional interfaces.
In this case, you are returning the return value of the last method in the method chain, orElse. ofNullable creates an Optional<T>, then map is called on this object and returns a new Optional<T>, then orElse is called and its return value is returned.
Lets go step by step:
ofNullable(entityValue)
creates an Optional of the incoming parameter (which is allowed to be null, using of() a NPE gets thrown for null input)
.map(entityUuid -> entityUuid.toString())
Then you pick the actual value, and invoke toString() on that value ... which only happens if entityValue isn't null. If it is null, the result comes from orElse(null).
In the end, the result of that operation on the Optional is returned as result of the method.
The above code is nothing but a glorified version of
if (entityValue == null) return null;
return entityValue.toString();
Optionals have their place in Java, but your example isn't a good one.
It doesn't help readability a bit, and you are not alone with wondering "what is going on here".
The code can be turn like this :
public String convertToDatabaseColumn(final UUID entityValue) {
if(entityValue==null){
return null;
}else{
return entityValue.toString();
}
}
Your initial code have two statements:
Optional.ofNullable(entityValue): create an Optional Object to say the value can be present or not.
.map(entityUuid -> entityUuid.toString()).orElse(null); you apply some operation to your Optional object, return a string of it or null.
This will avoid a null pointer exception in a more elegant way.
Optional.ofNullable(T value):
Returns an Optional describing the specified value, if non-null, otherwise returns an empty Optional.
Optional.orElse(null)
Return the value if present, otherwise return null.
Follow this link
I am trying to find the most concise (and meaningful) way of using Java Optional, to read the first value off a Optional<String> and return the String if exists, or return "NOT_FOUND". Here is the code I am working with:
public static String getValue(Optional<String> input) {
return input.ifPresent(val -> val.get()).orElse("NOT_FOUND")
}
The methods of Optional apparently have very specific purposes but the API has left me confused.
Update (4/13/2018):
The code in my question is incorrect, because if I regarded val as the value inside the Optional, then val.get() does not make any sense. Thanks for pointing that out, #rgettman.
Also, I added another part to my question in the accepted answer's comments, i.e. I needed a way to manipulate the String value, if present, before returning. The orElse("NOT_FOUND") is still applicable, if the Optional does not contain a value. So what is an acceptable use of the Optional API to achieve the following?
public static String getValue(Optional<String> input) {
return input.isPresent() ? input.get().substring(0,7).toUpperCase() : "NOT_FOUND";
}
#Aominè's answer and follow up comments addressed both parts of this question.
All you have to do is change your return statement to:
return input.orElse("NOT_FOUND");
This will return the object in the Optional if present else returns "NOT_FOUND".
That said, I'd avoid using Optional's as parameters. see here.
If you need to manipulate the string value, if it is present before returning it, use map method:
public static String getValue(Optional<String> input) {
return input.map(s -> s.substring(0,7).toUpperCase()).orElse("NOT_FOUND");
}
If input is empty the method returns default value - "NOT_FOUND", otherwise capitalized part of the string is returned.
getValue(Optional.ofNullable(null));
$6 ==> "NOT_FOUND"
getValue(Optional.of("some long string"));
$7 ==> "SOME LO"
I started to learn Lambda expressions of Java 8, and wrote below program to get sum of all numbers in the list:
import java.util.Arrays;
import java.util.List;
public class MainClass {
public static void main(String[] args) {
List<Integer> number = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(number.stream().reduce((c,e) -> {
return c + e;
}));
}
}
I was expecting the output to be:
15
but I got:
Optional[15]
Java version: 1.8.0_45
Please explain what does Optional[] means in the output?
Does it has any significance in Java 8?
From the Java Docs for Stream#reduce(), we see that the reduce operation returns an Optional<T>. An Optional simply wraps a value if there is a value present, otherwise is "empty".
Important operations on Optional include Optional#isPresent, which lets you know if there is something in the Optional or not, Optional#get, which returns the T wrapped in the Optional and throws an exception if called on Empty, and Optional#orElse which returns the T wrapped in the Optional if present, or the returns the default value provided if called on Empty.
For your case, the rationale behind reduce() returning an Optional<Integer> is that the list you're trying to reduce may be empty. In that case, the Integer that should be returned is not well defined. For your specific intention 0 would be acceptable (As the sum of the elements in an empty list is 0), thus you can get the sum as follows:
int sum = number.stream().reduce((c,e) -> c + e).orElse(0);
That way, even if the list is empty, you will still get a result that defines the sum of the list.
reduce(BinaryOperator<T> accumulator):
Returns an Optional describing the result of the reduction
Optional:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
The reason reduce() returns an Optional, is because the stream might be empty, in which case there would be nothing to reduce, aka no value, and an Optional.empty() would be returned.
In order to avoid Optional in the return you can call to this other method https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-T-java.util.function.BinaryOperator- Just add the identity: "0" before adding the lambda expression. Note that now there is only a 0 as a fist parameter to the reduce call.
System.out.println(number.stream().reduce(0,(c,e) -> {
return c + e;
}));
returns just
15
Got it, thanks #Mshnik and #TimoSta. According to source code of Optional<> which overrides toString method
#Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
Above code adds that Optional[] in my output stream.
From java.lang.Object.Optional:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
Optional offers two different primary methods for retrieving its value.
public T get() simply returns the value enclosed in the Optional, but throws a NoSuchElementException if the Optional does not wrap a value.
orElse(T other) returns the value enclosed in the Optional or other if the Optional does not enclose a value.
EDIT (thanks #Brian Goetz):
Generally, orElse() is a better choice since get() returns a NoSuchElementException if the Optional contains a null value. True, in this case you will always recieve a value in Optional but it's still good practice to primarily use orElse().
So, in your case, you would change
System.out.println(number.stream().reduce((c,e) -> {
return c + e;
}));
to:
System.out.println(number.stream().reduce((c,e) -> {
return c + e;
}).orElse(0));
which will return the desired value of 15.
And as #Brian Goetz said in the comments, if you really wanted to make it succinct you could use Integer::sum and a method reference:
System.out.println(number.stream.reduce(Integer::sum).orElse(0))
which is equivalent to using the longer lambda.
I want to get string values of my fields (they can be type of long string or any object),
if a field is null then it should return empty string, I did this with guava;
nullToEmpty(String.valueOf(gearBox))
nullToEmpty(String.valueOf(id))
...
But this returns null if gearbox is null! Not empty string because valueOf methdod returns string "null" which leads to errors.
Any Ideas?
EDIt: there are 100s fields I look for something easy to implement
You can use Objects.toString() (standard in Java 7):
Objects.toString(gearBox, "")
Objects.toString(id, "")
From the linked documentation:
public static String toString(Object o, String nullDefault)
Returns the result of calling toString on the first argument if the first argument is not null and returns the second argument otherwise.
Parameters:
o - an object
nullDefault - string to return if the first argument is null
Returns:
the result of calling toString on the first argument if it is not null and the second argument otherwise.
See Also:
toString(Object)
For java 8 you can use Optional approach:
Optional.ofNullable(gearBox).orElse("");
Optional.ofNullable(id).orElse("");
If you don't mind using Apache commons, they have a StringUtils.defaultString(String str) that does this.
Returns either the passed in String, or if the String is null, an empty String ("").
If you also want to get rid of "null", you can do:
StringUtils.defaultString(str).replaceAll("^null$", "")
or to ignore case:
StringUtils.defaultString(str).replaceAll("^(?i)null$", "")
If alternative way, Guava provides Strings.nullToEmpty(String).
Source code
String str = null;
str = Strings.nullToEmpty(str);
System.out.println("String length : " + str.length());
Result
0
Use an inline null check
gearBox == null ? "" : String.valueOf(gearBox);
StringUtils.defaultString(String str) Returns either the passed in String, or if the String is null, an empty String ("").
Example from java doc
StringUtils.defaultString(null) will return ""
StringUtils.defaultString("") will return ""
StringUtils.defaultString("bat") will return "bat"
Since you're using guava:
Objects.firstNonNull(gearBox, "").toString();
In Java 9+ use : Objects.requireNonNullElse (obj, defaultObj) https://docs.oracle.com/javase/9/docs/api/java/util/Objects.html#requireNonNullElse-T-T-
//-- returns empty string if obj is null
Objects.requireNonNullElse (obj, "")