Related
How can I use the Java Optional API to rewrite following code in a more elegant way:
first == null || second == null ? null : first + second;
The code should return null if any of the two variables is null or their sum elsewhere.
I can understand maybe you start to learn how to operate the Optional. How about this?
String result =
Optional.ofNullable(first)
// v--- the trick is use the `flatMap` here.
.flatMap(left -> Optional.ofNullable(second).map(right-> left + right))
.orElse(null);
If you are taking in nulls and returning nulls, then using Optional isn't very useful. You can wrap your code in Optional, but it will look just like your normal null checking code with some extra junk hanging around. Using Optional just to check for nulls is still just checking for nulls. If you rewrite your whole method to be fully Optional aware, you get something like the following:
public Optional<Integer> add(Optional<Integer> first, Optional<Integer> second)
{
return first.flatMap(left -> second.map(right -> left + right))
}
Notice how, by making full use of the Optional interface, you no longer need to worry about special processing for null. Additionally, if someone calls your method, the return type is much more specific about what happens on null/empty input.
If the input is out of your control, as you indicated in the comments, you can wrap it in an Optional using Optional.ofNullable, and then proceed. If both your input and output return type are fixed, then as nice as Optional is, you just don't have a good use for it.
If we stick to your requirement:
The code should return null if any of the two variables is null or their sum elsewhere.
Then you shouldn't use Optional at all. It will only make your code less readable and harder to maintain.
The true power of Optional doesn't reside in its elegance to avoid null-checks (nor in it's tempting potential to chain methods), but on its expressiveness to encapsulate either a present or an absent value. The best way to use it is as the return value of methods.
In your example, as you are saying that the method should return null if either operand is null, you are not taking advantage of Optional's potential. On the other hand, if you had a method that returned Optional (either empty or with the sum), you would be using it as expected:
public Optional<Integer> firstPlusSecond() {
Optional<Integer> a = Optional.ofNullable(first);
Optional<Integer> b = Optional.ofNullable(second);
if (!a.isPresent() || !b.isPresent()) {
return Optional.empty();
}
return Optional.of(a.get() + b.get());
}
This would in fact clearly express your intention, which is that the returned Optional is either empty (in case one operand is null) or holds the result of first + second.
It would be even better if you had optional getters for both first and second:
public Optional<Integer> first() {
return Optional.ofNullable(first);
}
public Optional<Integer> second() {
return Optional.ofNullable(second);
}
This way, the firstPlusSecond() method above would now turn to:
public Optional<Integer> firstPlusSecond() {
Optional<Integer> a = first();
Optional<Integer> b = second();
if (!a.isPresent() || !b.isPresent()) {
return Optional.empty();
}
return Optional.of(a.get() + b.get());
}
Which, IMO, is much better code.
Or even nicer, as suggested by #holi-java in the comments:
public Optional<Integer> firstPlusSecond() {
Optional<Integer> a = first();
Optional<Integer> b = second();
return a.isPresent() && b.isPresent() ?
Optional.of(a.get() + b.get()) :
Optional.empty();
}
Or, as again suggested by #holi-java, if you don't want to create optional getters for first and second, but still want to return an Optional, you might do it as follows:
public Optional<Integer> firstPlusSecond() {
return first != null && second != null ?
Optional.of(first + second) :
Optional.empty();
}
This is my solution using java stream
private Integer sum(Integer ...additions) {
return Arrays.stream(additions).filter(Objects::nonNull).reduce(0, Integer::sum);
}
i am sure this must have been asked before in different ways - as isEmptyOrNull is so common yet people implement it differently. but i have below curious query in terms of best available approach which is good for memory and performance both.
1) Below does not account for all spaces like in case of empty XML tag
return inputString==null || inputString.length()==0;
2) Below one takes care but trim can eat some performance + memory
return inputString==null || inputString.trim().length()==0;
3) Combining one and two can save some performance + memory (As Chris suggested in comments)
return inputString==null || inputString.trim().length()==0 || inputString.trim().length()==0;
4) Converted to pattern matcher (invoked only when string is non zero length)
private static final Pattern p = Pattern.compile("\\s+");
return inputString==null || inputString.length()==0 || p.matcher(inputString).matches();
5) Using libraries like -
Apache Commons (StringUtils.isBlank/isEmpty)
or Spring (StringUtils.isEmpty)
or Guava (Strings.isNullOrEmpty)
or any other option?
Useful method from Apache Commons:
org.apache.commons.lang.StringUtils.isBlank(String str)
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/StringUtils.html#isBlank(java.lang.String)
To detect if a string is null or empty, you can use the following without including any external dependencies on your project and still keeping your code simple/clean:
if(myString==null || myString.isEmpty()){
//do something
}
or if blank spaces need to be detected as well:
if(myString==null || myString.trim().isEmpty()){
//do something
}
you could easily wrap these into utility methods to be more concise since these are very common checks to make:
public final class StringUtils{
private StringUtils() { }
public static bool isNullOrEmpty(string s){
if(s==null || s.isEmpty()){
return true;
}
return false;
}
public static bool isNullOrWhiteSpace(string s){
if(s==null || s.trim().isEmpty()){
return true;
}
return false;
}
}
and then call these methods via:
if(StringUtils.isNullOrEmpty(myString)){...}
and
if(StringUtils.isNullOrWhiteSpace(myString)){...}
Just to show java 8's stance to remove null values.
String s = Optional.ofNullable(myString).orElse("");
if (s.trim().isEmpty()) {
...
}
Makes sense if you can use Optional<String>.
This one from Google Guava could check out "null and empty String" in the same time.
Strings.isNullOrEmpty("Your string.");
Add a dependency with Maven
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
with Gradle
dependencies {
compile 'com.google.guava:guava:20.0'
}
Haven't seen any fully-native solutions, so here's one:
return str == null || str.chars().allMatch(Character::isWhitespace);
Basically, use the native Character.isWhitespace() function. From there, you can achieve different levels of optimization, depending on how much it matters (I can assure you that in 99.99999% of use cases, no further optimization is necessary):
return str == null || str.length() == 0 || str.chars().allMatch(Character::isWhitespace);
Or, to be really optimal (but hecka ugly):
int len;
if (str == null || (len = str.length()) == 0) return true;
for (int i = 0; i < len; i++) {
if (!Character.isWhitespace(str.charAt(i))) return false;
}
return true;
One thing I like to do:
Optional<String> notBlank(String s) {
return s == null || s.chars().allMatch(Character::isWhitepace))
? Optional.empty()
: Optional.of(s);
}
...
notBlank(myStr).orElse("some default")
Apache Commons Lang has StringUtils.isEmpty(String str) method which returns true if argument is empty or null
springframework library Check whether the given String is empty.
f(StringUtils.isEmpty(str)) {
//.... String is blank or null
}
Optional.ofNullable(label)
.map(String::trim)
.map(string -> !label.isEmpty)
.orElse(false)
OR
TextUtils.isNotBlank(label);
the last solution will check if not null and trimm the str at the same time
In most of the cases, StringUtils.isBlank(str) from apache commons library would solve it. But if there is case, where input string being checked has null value within quotes, it fails to check such cases.
Take an example where I have an input object which was converted into string using String.valueOf(obj) API. In case obj reference is null, String.valueOf returns "null" instead of null.
When you attempt to use, StringUtils.isBlank("null"), API fails miserably, you may have to check for such use cases as well to make sure your validation is proper.
Simply and clearly:
if (str == null || str.trim().length() == 0) {
// str is empty
}
With the openJDK 11 you can use the internal validation to check if the String is null or just white spaces
import jdk.internal.joptsimple.internal.Strings;
...
String targetString;
if (Strings.isNullOrEmpty(tragetString)) {}
You can make use of Optional and Apache commons Stringutils library
Optional.ofNullable(StringUtils.noEmpty(string1)).orElse(string2);
here it will check if the string1 is not null and not empty else it will return string2
If you have to test more than one string in the same validation, you can do something like this:
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class StringHelper {
public static Boolean hasBlank(String ... strings) {
Predicate<String> isBlank = s -> s == null || s.trim().isEmpty();
return Optional
.ofNullable(strings)
.map(Stream::of)
.map(stream -> stream.anyMatch(isBlank))
.orElse(false);
}
}
So, you can use this like StringHelper.hasBlank("Hello", null, "", " ") or StringHelper.hasBlank("Hello") in a generic form.
We can make use of below
Optional.ofNullable(result).filter(res -> StringUtils.isNotEmpty(res))
.ifPresent( s-> val.set(s));
If I want to total a list of accounts' current balances, I can do:
accountOverview.setCurrentBalance(account.stream().
filter(a -> a.getCurrentBalance() != null).
mapToLong(a -> a.getCurrentBalance()).
sum());
But this expression will return 0, even if all the balances are null. I would like it to return null if all the balances are null, 0 if there are non-null 0 balances, and the sum of the balances otherwise.
How can I do this with a lambda expression?
Many thanks
Once you filtered them from the stream, there's no way to know if all the balances were null (unless check what count() returns but then you won't be able to use the stream since it's a terminal operation).
Doing two passes over the data is probably the straight-forward solution, and I would probably go with that first:
boolean allNulls = account.stream().map(Account::getBalance).allMatch(Objects::isNull);
Long sum = allNulls ? null : account.stream().map(Account::getBalance).filter(Objects::nonNull).mapToLong(l -> l).sum();
You could get rid of the filtering step with your solution with reduce, although the readability maybe not be the best:
Long sum = account.stream()
.reduce(null, (l1, l2) -> l1 == null ? l2 :
l2 == null ? l1 : Long.valueOf(l1 + l2));
Notice the Long.valueOf call. It's to avoid that the type of the conditional expression is long, and hence a NPE on some edge cases.
Another solution would be to use the Optional API. First, create a Stream<Optional<Long>> from the balances' values and reduce them:
Optional<Long> opt = account.stream()
.map(Account::getBalance)
.flatMap(l -> Stream.of(Optional.ofNullable(l)))
.reduce(Optional.empty(),
(o1, o2) -> o1.isPresent() ? o1.map(l -> l + o2.orElse(0L)) : o2);
This will give you an Optional<Long> that will be empty if all the values were null, otherwise it'll give you the sum of the non-null values.
Or you might want to create a custom collector for this:
class SumIntoOptional {
private boolean allNull = true;
private long sum = 0L;
public SumIntoOptional() {}
public void add(Long value) {
if(value != null) {
allNull = false;
sum += value;
}
}
public void merge(SumIntoOptional other) {
if(!other.allNull) {
allNull = false;
sum += other.sum;
}
}
public OptionalLong getSum() {
return allNull ? OptionalLong.empty() : OptionalLong.of(sum);
}
}
and then:
OptionalLong opt = account.stream().map(Account::getBalance).collect(SumIntoOptional::new, SumIntoOptional::add, SumIntoOptional::merge).getSum();
As you can see, there are various ways to achieve this, so my advice would be: choose the most readable first. If performance problems arise with your solution, check if it could be improved (by either turning the stream in parallel or using another alternative). But measure, don't guess.
For now, I'm going with this. Thoughts?
accountOverview.setCurrentBalance(account.stream().
filter(a -> a.getCurrentBalance() != null).
map(a -> a.getCurrentBalance()).
reduce(null, (i,j) -> { if (i == null) { return j; } else { return i+j; } }));
Because I've filtered nulls already, I'm guaranteed not to hit any. By making the initial param to reduce 'null', I can ensure that I get null back on an empty list.
Feels a bit hard/confusing to read though. Would like a nicer solution..
EDIT Thanks to pbabcdefp, I've gone with this rather more respectable solution:
List<Account> filtered = account.stream().
filter(a -> a.getCurrentBalance() != null).
collect(Collectors.toList());
accountOverview.setCurrentBalance(filtered.size() == 0?null:
filtered.stream().mapToLong(a -> a.getCurrentBalance()).
sum());
You're trying to do two fundamentally contradicting things: filter out null elements (which is a local operation, based on a single element) and detect when all elements are null (which is a global operation, based on the entire list). Normally you should do these as two separate operations, that makes things a lot more readable.
Apart from the reduce() trick you've already found, you can also resort to underhand tricks, if you know that balance can never be negative for example, you can do something like
long sum = account.stream().
mapToLong(a -> a.getCurrentBalance() == null ? 0 : a.getCurrentBalance()+1).
sum() - account.size();
Long nullableSum = sum < 0 ? null : sum;
But you've got to ask yourself: is what you gain by only iterating across your collection once worth the cost of having written a piece of unreadable and fairly brittle code? In most cases the answer will be: no.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
The following statement just looks very messy when you have a lot of terms:
if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
//Do something
Is there a cleaner way of performing the same action, I would like my code to be as readable as possible.
NOTE: x, y and z are just placeholders for any string of any length. There could be 20 string terms here of variable length in if condition each being OR'd together
What do you think looks "unclean" about it?
If you have a bunch of complicated boolean logic, you might separate the different parts of it into individual boolean variables and refer to them in the if statement.
Or you could create a function that takes your 'a' variable and returns a boolean. You'd just be hiding your logic in the method, but it would clean up your if statement.
Set<String> stuff = new HashSet<String>();
stuff.add("x");
stuff.add("y");
stuff.add("z");
if(stuff.contains(a)) {
//stuff
}
If this is a tight loop you can use a static Set.
static Set<String> stuff;
static {
stuff = new HashSet<String>();
stuff.add("x");
stuff.add("y");
stuff.add("z");
}
//Somewhere else in the cosmos
if(stuff.contains(a)) {
//stuff
}
And if you want to be extra sure nothing is getting modified while you're not looking.
Set<String> test = Collections.unmodifiableSet(new HashSet<String>() {
{
add("x");
add("y");
add("z");
}
});
If you just want to get some logic in there for a handful of hard coded conditions then one of the switch or if statement with newlines solutions might be better. But if you have a lot of conditions then it might be good to separate your configuration from logic.
Alternatively, if you are using Java 7+ you can use strings in switch/case. For example (I extracted this from an Oracle doc and modified)
switch (str) {
case "x":
case "y":
case "z":
//do action
break;
default:
throw new IllegalArgumentException("argument not matched "+str);
}
Here is the link
Use a regular expression
If (a.matches("[xyz]")){
// matches either "x", "y", or "z"
or, for longer strings,
If (a.matches("one|two|three")){
// matches either "one", "two" or "three"
But this is computationally expensive, but probably not much worse than instantiating a set etc. But it's the clearest way I can think of.
But in the end, the nicest way is probably to leave things as they are, with an adjustment to the formatting:
if (a.equals("x") ||
a.equals("y") ||
a.equals("z")
){
There is then absolutely no ambiguity in what the code is doing and so your code will be easier to maintain. If performance matters, you can even put the most likely occurrences towards the top of the list.
Reaching for semantics
On a semantic level, what you are checking for is set membership. However, you implement it on a very low level, basically inlining all the code needed to achieve the check. Apart from forcing the reader to infer the intent behind that massive condition, a prominent issue with such an approach is the large number of degrees of freedom in a general Boolean expression: to be sure the whole thing amounts to just checking set membership, one must carefully inspect each clause, minding any parentheses, misspellings of the repeated variable name, and more.
Each loose degree of freedom means exposure to not just one more bug, but to one more class of bugs.
An approach which uses an explicit set would have these advantages:
clear and explicit semantics;
tight constraint on the degrees of freedom to look after;
O(1) time complexity vs. O(n) complexity of your code.
This is the code needed to implement a set-based idiom:
static final Set<String> matches =
unmodifiableSet(new HashSet<>(asList("a","b","c")));
...
if (matches.contains(a)) // do something;
*I'm implying import static java.util.Arrays.asList and import static java.util.Collections.unmodifiableSet
Readability Is Mostly Formatting
Not readable...
if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
//Do something
Now easy to real...
if(a.equals("x") ||
a.equals("y") ||
a.equals("z") ||
Any number of terms...... )
//Do something
Readability is very subjective to the person reading the source code.
If I came across code that implements collections, loops or one of the many other complicated answers here. I'd shake my head in disbelieve.
Separate The Logic From The Problem
You are mixing two different things. There is the problem of making the business logic easy to read, and the problem of implementing the business logic.
if(validState(a))
// Do something
How you implement validState doesn't matter. What's important is that code with the if statement is readable as business logic. It should not be a long chain of Boolean operations that hide the intent of what is happening.
Here is an example of readable business logic.
if(!isCreditCard(a)) {
return false;
}
if(isExpired(a)) {
return false;
}
return paymentAuthorized(a);
At some level there has to be code that processes basic logic, strings, arrays, etc.. etc.. but it shouldn't be at this level.
If you find you often have to check if a string is equal to a bunch of other strings. Put that code into a string utility class. Separate it from your work and keep your code readable. By ensuring it shows what you're really trying to do.
You can use Arrays.asList().This is the simplest approach and less verbosity.
Arrays.asList("x","y","z"...).contains(a)
For performance reason if your collection is too big you could put data in a HashSet cause searching there is in constant time.
Example make your own util method
public final class Utils{
private Utils(){}//don't let instantiate
public static <T> boolean contains(T a,T ... x){
return new HashSet<>(Arrays.asList(x)).contains(a);
}
}
Then in your client code:
if(Utils.contains(a,"x","y","z","n")){
//execute some code
}
With a little bit of help, you can get the syntactic sugar of a nicer if-statement with just a tiny bit of overhead. To elaborate on Tim's recommendation and Jesko's recommendation a tad further...
public abstract class Criteria {
public boolean matchesAny( Object... objects ) {
for( int i = 0, count = objects.length; i < count; i++ ) {
Object object = objects[i];
if( matches( object ) ) {
return true;
}
}
return false;
}
public boolean matchesAll( Object... objects ) {
for( int i = 0, count = objects.length; i < count; i++ ) {
Object object = objects[i];
if( !matches( object ) ) {
return false;
}
}
return true;
}
public abstract boolean matches( Object object );
}
public class Identity extends Criteria {
public static Identity of( Object self ) {
return new Identity( self );
}
private final Object self;
public Identity( Object self ) {
this.self = self;
}
#Override
public boolean matches( Object object ) {
return self != null ? self.equals( object ) : object == null;
}
}
Your if-statement would then look like this:
if( Identity.of( a ).matchesAny( "x", "y", "z" ) ) {
...
}
This is sort of a middle ground between having a generic syntax for this sort of conditional matching and having the expression describe a specific intent. Following this pattern also lets you perform the same sort of matching using criteria other than equality, much like how Comparators are designed.
Even with the improved syntax, this conditional expression is still just a little bit too complex. Further refactoring might lead to externalizing the terms "x", "y", "z" and moving the expression into a method whose name clearly defines its intent:
private static final String [] IMPORTANT_TERMS = {
"x",
"y",
"z"
};
public boolean isImportant( String term ) {
return Identity.of( term ).matchesAny( IMPORTANT_TERMS );
}
...and your original if-statement would finally be reduced to...
if( isImportant( a ) ) {
...
}
That's much better, and now the method containing your conditional expression can more readily focus on Doing One Thing.
Independent of what you are trying to achieve, this
if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
//Do something
is always messy and unclean. In the first place it is just too long to make sense of it quickly.
The simplest solution for me would be to express your intend instead of being explicit.
Try to do this instead:
public class SomeClass{
public void SomeMethod(){
if ( matchesSignificantChar(a) ){
//doSomething
}
}
private bool matchesSignificantChar(String s){
return (s.equals("x") || s.equals("y") || s.equals("z") || Any number of terms...... )
}
}
This simplifies the scope of your conditional statement and makes it easier to understand while moving the complexity to a much smaller and named scope, that is headed by your intend.
However, this is still not very extensible. If you try to make it cleaner, you can extract the boolean method into another class and pass it as a delegate to SomeClass'es Constructor or even to SomeMethod. Also you can look into the Strategy Pattern for even more exensiblity.
Keep in mind that as a programmer you will spend much more time reading code (not only yours) than writing it, so creating better understandable code will pay off in the long run.
I use following pattern
boolean cond = false; // Name this variable reasonably
cond = cond || a.equals("x");
cond = cond || a.equals("y");
cond = cond || a.equals("z");
// Any number of terms......
if (cond) {
// ...
}
Note: no objects created on the heap. Also you can use any conditions, not only "equals".
In ruby you can use operator ||= for this purpose like cond ||= a.equals("x").
The Set answer is good. When not comparing for membership of a collection you can also separate out some or all of the conditional statement into methods. For example
if (inBounds(x) && shouldProcess(x) ) {
}
If a is guaranteed to be of length 1, you could do:
if ("xyz".indexOf(a) != -1)
One really nice way to do something like this is to use ASCII values, assuming your actual case here is where a is a char or a single character string. Convert a to its ASCII integer equivalent, then use something like this:
If you want to check that a is either "t", "u", "v", ... , "z", then do.....
If (val >= 116 && val <= 122) {//code here}
I prefer to use regexp like few guys wrote upper.
But also you can use next code
private boolean isOneMoreEquals(Object arg, Object... conditions) {
if (conditions == null || arg == null) {
return false;
}
for (int i = 0, d = conditions.length; i < d; i++) {
if (arg.equals(conditions[i])) {
return true;
}
}
return false;
}
so your code will be next:
if (isOneMoreEquals(a, "x", "y", "z") {
//do something
}
Assuming that your "x", "y", and "z" can be of arbitrary length, you can use
if (0 <= java.util.Arrays.binarySearch(new String[] { "x", "y", "z" }, a)) {
// Do something
}
Just make sure that you list your items in lexicographic order, as required by binarySearch(). That should be compatible all the way back to Java 1.2, and it should be more efficient than the solutions that use Java Collections.
Of course, if your "x", "y", and "z" are all single characters, and a is also a character, you can use if (0 <= "xyz".indexOf(a)) { ... } or
switch (a) {
case 'x': case 'y': case 'z':
// Do something
}
If x,y,z... is Consecutiveļ¼ you can use if(a >= 'x' && a <= '...'), if not, you can use ArrayList or just Arrays.
I think that cleanest and fastest way is to put values in array.
String[] values={"value1","value2","value3"};
for (string value : values) {
if (a.equals(value){
//Some code
}
}
I'm not really sure what this is called so it's hard to look it up and it is best if I show you what I'm trying to do.
I want to create a condional variable of sorts
String fileName = (if (this.filename != null) { return this.filename; }
else { return "default value"; });
This should be pretty clear on what I'm trying to do. I want to use some sort of condition to set this variable based on another variables input, in this case whether or not it equals null or not.
Use the ternary operator. In my opinion, this is one of strategy in defensive programming.
String fileName = (this.filename != null? this.filename : "default value");
String fileName = this.filename != null ? this.filename : "default value";
Or, more verbose but (perhaps) easier to understand
String aFilename;
if (this.filename != null)
aFilename = this.filename;
else
aFilename = "Default Value";
return aFilename;
I prefer Careal's code but YMMV. Some find the ? operator complicated (especially in messy cases)
Also, when stepping though with the debugger this code will be way easier to see what happened.
You can use ternary operator: boolean expression ? value1 : value2
String fileName = fileName == null ? "Default value" : this.filename;