A cleaner if statement with multiple comparisons [closed] - java

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
}
}

Related

Arrays.equals without length of arrays

I have two arrays with different length, but same elements. For example
A1 = {1,2,3,null,null}
A2 = {1,2,3}
Arrays.equals gives me false, because arrays have different length. Are there any method in java that will compare only elements in method?
I don't want to use .toString
I'm trying to make compare method in my own generic stack realization.
No, because its a weird request. null does not mean 'not here', null means 'unknown / unset', that's why it throws exceptions when you interact with it: You're asking "hey, thing that has not been set yet, are you X", and there is no way to answer such a question.
That doesn't mean your code is wrong, just, you can stop looking for existing implementations. Weird requests generally aren't catered to by the core libraries (or any other). You also may want to change your mindset on null. Programming in java is a lot less aggravating if at all times a NullPointerException is a good thing. In other words, avoid using null as having any semantic meaning. If you ever write if (x == null || x.isEmpty()) you are doing it wrong. Instead, where-ever 'x' is coming from, it should hold, or be updated to ASAP, the empty string instead. So, if reading in external data (e.g. you marshalled some JSON into an object), do a 'clean' step that replaces all null values that have semantic meaning with an object that actually represents it, and for methods that return stuff, always return an object that represents what you are returning - only return null if you WANT to convey the notion that there is no result (i.e. that's not the same as 'an empty result', i.e. if any code acts like there was a result, you want it to crash).
In other words, I doubt you are asking the right question. But in case you are, you have two broad options.
First make null-less arrays then compare those as normal
One option is to make new arrays that have nulls stripped. Something like:
#SuppressWarnings("unchecked")
<T> T[] stripNulls(T[] in) {
Class<?> componentType = in.getClass().getComponentType();
return (T[]) Arrays.stream(in)
.filter(x -> x != null)
.toArray(len -> java.lang.reflect.Array.newInstance(componentType, len));
}
// which you can then use; you don't need generics for a compare,
// it wouldn't add anything at all.
boolean compare(Object[] a, Object[] b) {
return Arrays.equals(stripNulls(a), stripNulls(b));
}
Just compare in place
If it's performance sensitive that's suboptimal. A better approach would involve a little more coding:
boolean compare(Object[] a, Object[] b) {
Object ae = null, be = null;
int ai = 0, bi = 0, al = a.length, bl = b.length;
while (true) {
/* set `ae` and `be` to the next non-null element */
while (ae == null && ai < al) ae = a[ai++];
while (be == null && bi < bl) be = b[bi++];
/* Have we hit the end? */
if (ai == al && bi == bl) return true;
/* If one is at the end, but the other isn't... */
if (ai == al || bi == bl) return false;
/* check if the 2 current elements are equal */
if (!ae.equals(be)) return false;
}
}
Not a native Java Developer, but maybe this helps you?
boolean arraysEqual = Arrays.equals(Arrays.stream(a1).filter(n => n != null).toArray(), Arrays.stream(a2).filter(n => n != null).toArray())

Convert nested loops into a Stream

I want to replace nested for loops in the following code with streams:
private boolean check(St st) {
List<Co> prereqs = getCoPrereqs();
for (Co prereq : prereqs) {
List<En> stEns = st.getEns();
boolean flag = false;
for (En en : stEns) {
if (en.getCo().equals(prereq) && en.getGr() != null) {
if (en.hasPassedCo()) {
flag = true;
}
}
if (!flag)
return false;
}
}
return true;
}
The two loops and the variable flag is causing confusion. I am not sure if this can be converted to streams totally.
I have simplified your code somewhat by doing the following:
removing the boolean flag. It isn't necessary.
get the List<En> just one time outside of the Prereq loop. You can reiterate the original as often as necessary.
The major difference is to check for a false return from en.hasPassedCo() and return false immediately. Once the iterations are complete, then return true.
private boolean check(St st) {
List<Co> prereqs = getCoPrereqs();
List<En> stEns = st.getEns();
for (Co prereq : prereqs) {
for (En en : stEns) {
if (en.getCo().equals(prereq) && en.getGr() != null) {
if (!en.hasPassedCo()) {
return false;
}
}
}
}
return true;
}
I'm not certain that streams would improve this (at least not knowing more about the relationships of the fields to each other). Also, it doesn't make sense how Co relates to en.getCo. Seems to me that something like prereqs.contains(en.getCo()) would be more appropriate.
Probably, you can use nested streams with allMatch.
I'm saying "probably" because I can't be sure that the code you've proved does what expected, types name are not self-explanatory at all (names in the code matter a lot) and you have not accompanied the code with any explanations.
If I understood your code correctly, you need to validate every Co object returned by getCoPrereqs() and that entails checking each Co object against En object from a List<En> which should be extracted from the method parameter.
That's how it might look like:
private boolean check(St st){
return getCoPrereqs().stream()
.allMatch((Co prereq) -> st.getEns().stream()
.allMatch((En en) -> en.getCo().equals(prereq)
&& en.getGr() != null
&& en.hasPassedCo()
));
}
For readability reasons (to make it more easier to compare stream with loops), I've used explicitly typed lambda expressions (the common practice is to omit types for brevity and let the type inference do the job).

Optimize Java Regular expression

I have a file with huge if statements like this:
if ((Pattern.compile("string1|String2|String3").matcher(text_str).find())
&& (Pattern.compile("String4|String5").matcher(text_str).find())
&& (Pattern.compile("String6|String7|String8").matcher(text_str).find())
&& (Pattern.compile("String9|String10").matcher(text_str).find())
&& (Pattern.compile("String11|String12").matcher(text_str).find())
&& (Pattern.compile("String13|String14").matcher(text_str).find())
&& (Pattern.compile("String15|String16").matcher(text_str).find())
&& (Pattern.compile("String17|String18").matcher(text_str).find())
&& (Pattern.compile("String19|String19|String20").matcher(text_str).find())
) {
return true;
}
I basically need to do checks for a strings like (Pseudocode):
String contains? (I have a) AND (cat OR dog OR fish) AND (and it) AND (eats OR drinks OR smells) AND (funny OR a lot OR nothing)
how would I make this more maintainable and efficient with a very big amount of checks?
You can do that with one regex using a series of look-aheads:
return text_str.matches("(?s)^(?=.*(string1|String2|String3))(?=.*(String4|String5))(?=.*(String6|String7|String8))(?=.*(String9|String10))(?=.*(String11|String12))(?=.*(String13|String14))(?=.*(String15|String16))(?=.*(String17|String18))(?=.*(String19|String19|String20))");
Well you could have a List<List<String>> which you can compile into List<Pattern>:
for(List<String> terms : listOfTerms) {
String pattern = StringUtils.join(terms, "|");
patterns.add(Pattern.compile(pattern));
}
and then check:
for(Pattern p : patterns)
if(!p.matches(string))
return false;
return true;
This should make the checking easier. For defining the initial list of terms maybe Arrays would actually work better? Something like this:
String[][] terms = {{"cat", "dog"}, {"a", "b"}...};
Which could be formatted to look nice and could contain comments etc...

Vector<Customer> C++, List<Customer> & Vector<Customer> Java

I learned this piece of code in University, while learning C++.. and I later used the same thing in C#... but now I want to use it in Java... I have looked all over Internet for similar thing, but i dun even no how to phrase it so i get the correct results.
So umm please let me know how to do this is in JAVA and also let me know what is this way called??? I know What it does.. but i have no idea how it does it.. so mind explaining it as well...
C++ is the same thing as below except one DIFFERENCE look Below
C# if (Customers[i].delExecute(delIn) == true)
C++ if (Customers[i]->delExecute(delIn) == true)
Java ?? if (????????????????????????????????)
So here I go ill try my best to explain.
C#
Class called Customer with custId etc etc
List<Customer> Customers = new List<Customers>
public void delCust(int delIn)
{
for (int i = 0; i < Customers.Count(); i++)
{
if (Customers[i].delExecute(delIn) == true)
{
Customers.Remove(Customers[i]);
break;
}
}
}
bool delExecute(int delInput) {
if (custId == delInput) {
return true;
}
return false;
}
OK right so the above code works
now I want the same thing with JAVA... anyone got any ideas how?
if (Customers.get(i).delExecute(delIn))
BTW, there is no need to say == true explicitly
In Java, Vector is an out-dated class which you should probably avoid using. Instead, you should use an ArrayList. Either way, though, both are Lists, and thus implement get for random-access.
You can implement what you're attempting as follows...
if (customers.get(i).delExecute(delIn))
Note that == true is redundant, as it is effectively an identity (true == true is true, false == true is false). You should also avoid capitalized field names in Java.
Now, there is also a preferred way to do what you are attempting using an Iterator.
private List<Customer> customers = new ArrayList<Customers>();
public void delCust(int delIn) {
final Iterator<Customer> cursor = customers.iterator();
while (cursor.hasNext()) {
if (cursor.next().delExecute(delIn)) {
cursor.remove();
break;
}
}
}
... coupled with:
boolean delExecute(int delInput) {
return custId == delInput;
}

Is there any appreciable difference between if and if-else?

Given the following code snippets, is there any appreciable difference?
public boolean foo(int input) {
if(input > 10) {
doStuff();
return true;
}
if(input == 0) {
doOtherStuff();
return true;
}
return false;
}
vs.
public boolean foo(int input) {
if(input > 10) {
doStuff();
return true;
} else if(input == 0) {
doOtherStuff();
return true;
} else {
return false;
}
}
Or would the single exit principle be better here with this piece of code...
public boolean foo(int input) {
boolean toBeReturned = false;
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
}
return toBeReturned;
}
Is there any perceptible performance difference? Do you feel one is more or less maintainable/readable than the others?
With the second example you state very clearly that both conditions are mutually exclusive.
With the first one, it is not so clear, and in the (unlikely) event that an assignment to input is added between both ifs, the logic would change.
Suppose someone in the future adds input = 0 before the second if.
Of course this is unlikely to happen, but if we are talking about maintainability here, if-else says clearly that there are mutually exclusive conditions, while a bunch of ifs don't, and they are not so dependent between each other as are if-else blocks.
edit:Now that I see, in this particular example, the return clause forces the mutual exclusivity, but again, we're talking about maintainability and readability.
Anyway, about performance, if this is coded in Java you shouldn't care for performance of a couple of if blocks, if it were embedded C in a really slow hardware, maybe, but certainly not with java.
Use whatever form best describes your intent.
Do not follow the single exit principle if things are this simple, though--it just makes it more confusing.
In the first:
somebody eventually, by some strange reason and when you're not looking will add some add statement that will make this method fail under certain strange conditions, everybody ( or worst, one single person ) will spend 4 hrs. watching the source code and debugging the application to finally found there was something in the middle.
The second is definitely better, not only it prevents this scenario, but also helps to clearly state , it this or this other no more.
If all the code we write within an if where 10 lines long at most, this wouldn't matter really, but unfortunately that's not the case, there exists other programmers which by some reason think that a if body should be > 200 lines long... anyway.
I don't like the third, it forces me to look for the return variable, and it's easier to find the return keyword
About speed performance, they are ( almost ) identical. Don't worry about that.
In your last example, don't do this:
public boolean foo(int input) {
boolean toBeReturned = false;
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
}
return toBeReturned;
}
but this (notice the use of Java's final):
public boolean foo(int input) {
final boolean toBeReturned; // no init here
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
} else {
toBeReturned = false;
}
return toBeReturned;
}
By doing so you make your intend clear and this is a godsend for IDEs supporting "programming by intention" (there's no need to "compile" to see potential errors, even on a partial AST, a good IDE can examine incomplete source in real-time and give you instant warnings).
This way you are sure not to forget to initialize your return value. This is great if later on you decide that after all you need another condition.
I do this all the time and even moreso since I started using IntelliJ IDEA (version 4 or so, a long time ago) and this has saved me so many silly distraction mistakes...
Some people will argue that this is too much code for such a simple case but that's entirely missing the point: the point is to make the intent clear so that the code reads easily and can be easily extended later on, without accidentally forgetting to assign toBeReturned and without accidentally forgetting to return from a later clause you may add.
Otherwise, if "conciseness" was the name of the game, then I'd write:
public boolean foo(int a) {
return a > 10 ? doStuff() : a == 0 ? doOtherStuff() : false;
}
Where both doStuff and doOtherStuff would return true.
Semantically — no. Performance-wise this depends on compiler, i.e. whether it can spot that both conditions cannot be true at once. I'd bet standard Sun compiler can. Whether to use single exit principle depends on tastes. I personally hate it.
Version #1 and #2 may be faster than #3, but I suppose the performance difference is minimal. I would rather focus on readability.
Personally, I would never use version #2. Between #1 and #3, I would choose the one that yields the most readable code for the case in question. I don't like many exit points in my methods, because it makes the code hard to analyze. However, there are cases where the flow becomes clearer when we exit immediately for some special cases, and continue with the main cases.
Think of this case when the two examples won't be similar:
public boolean foo(int input) {
if (input > 10) {
// doStuff();
return true;
}
System.out.println("do some other intermediary stuff");
if (input == 0) {
// doOtherStuff();
return true;
}
return false;
}
vs.
public boolean foo(int input) {
if (input > 10) {
// doStuff();
return true;
}
//System.out.println("doing some intermediary stuff... doesn't work");
else if (input == 0) {
// doOtherStuff();
return true;
} else {
return false;
}
return false;
}
The first approach is probably more flexible, but both formulas have their use in different circumstances.
Regarding performance, I think the differences are to small to be taken in consideration, for any regular java application, coded by sane programmers :).
In your case the second if would only get called if the first if failed so it's less important here but if your first if did something and didn't return, the second if (which would then always be false) would still be tested unless it was in an else-if.
In other words, there are cases where the difference between if-else-if and if-if matters, but this isn't one of them.
Example: Try this and then try it after removing the else. You get two different outputs:
int someNumber = 1;
if(someNumber < 5)
{
someNumber += 5;
Console.WriteLine("First call.");
}
else if(someNumber >= 5)
{
Console.WriteLine("Second call.");
}
Between the first and second snippets, there's really no difference. However the third snippet is quite inefficient. Because you wait to return control of the program to the caller until the last line of code in the method, you waste processing power/memory whereas the first two code snippets return control as soon as it determines one of the conditions to be true.

Categories