Best way to check multiple strings in an if statement - java

What is the cleanest way of checking multiple strings in an if statement, I want to be able to check to see if the users country is one that uses the euro which I will put in the ("???") .Because this works.
if (usercountry.equals("FRA") || usercountry.equals("FRA")||
usercountry.equals("FRA") || usercountry.equals("FRA") ||
usercountry.equals("FRA") || usercountry.equals("FRA") ||
usercountry.equals("FRA") || usercountry.equals("FRA") ||
usercountry.equals("FRA")) {
costpermile = costpermile*1.42; //(costpermile=£) (costpermile*1.42=Euros)
}
but it looks awful
BTW im not checking France over and over again its still prototype code and so I haven't entered every euro country without checking if there was a better way first.

1. Regex
if (usercountry.matches("FRA|GER|ITA"))
{
costpermile = costpermile*1.42;
}
2. Add countries to a data structure (Set) and check
Set<String> eurocountries= new HashSet<String>();
eurocountries.add("FRA");eurocountries.add("GER");eurocountries.add("ITA");
if (eurocountries.contains(usercountry))
{
costpermile = costpermile*1.42;
}
Note: I think its the regex method you're looking for

If you're using Java 7 or later you can use a switch statement on a String like so
switch(userCountry)
{
case "FRA":
costpermile = costpermile*1.42;
break;
default:
break;
}
Then you can just add whatever additional cases you need.

You could store the strings in an array and then iterate over it like this:
String[] str = {"EN", "FRA", "GER"};
for (String s : str) {
if (usercountry.equals(s)) {
// Match: do something...
}
}

As others have suggested, you could use a Set for storing the country codes:
private static final Set<String> EURO_COUNTRIES
= new HashSet<>(Arrays.asList("FRA", "ESP", "ITA", "GER" /*etc..*/));
Then in your code, you can check the country in the following way:
String userCountry = Locale.getDefault().getISO3Country();
if (EURO_COUNTRIES.contains(userCountry)) {
// do something
}
However, a better long-term solution might be creating a rich enum, especially if you need to attach more logic with these country codes.

You could do something like this:
String euroCountries [] = {"FRA", "DEU", ...}
public boolean isEuroCountry(String userCountry){
for(String country : euroCountries){
if(usercountry.equals(country)){
return true;
}
}
return false;
}

You could append a prefix for each country that belongs to a particular continent then just check for that token.
For e.g. in Europe countries:
E_FRA
E_BEL
E_GER
...
would be E
Asian countries:
A_CHN
A_MLY
A_PHL
...
would be A, and so on.
if ( userCountry.startsWith("E") ) {
// Europe countries
} else
if ( userCountry.startsWith("A") ) {
// Asian countries
}
...

String countries[] = {"FRA", "GER", "ENG"} // declaration of the countries you want to list.
// function to calculate the cost per mile
public double calculateCostPerMile(String userCountry){
double costPerMile;
for(String country: countries){
if(country.equals(userCountry)){
return costPerMile*1.42; // return value
}
}
}

Related

Java ( Reading userinput.equalsIgnoreCase() in Arraylist)

I was writing a list of menu for my product and wanted to use a simple String (and wanted to use .equalsIgnoreCase() so that it would ignore whatever text casing it is) and compare it in ArrayList pre-coded (as i was adding a new product) using .contain(); however it still depends on text casing and I couldn't find answers. Hoping that someone would help me :).
static void AddProductCode() {
boolean print = true;
for (int i = 0; i < product.size(); i++) {
System.out.println(productcode.get(i)+" " +product.get(i)+" "+ productprice.get(i));
}
System.out.print("PRODUCT CODE : ");
code = scan.next();
code.equalsIgnoreCase(code);
boolean check = productcode.contains(code);
if(check == true){
System.out.println("CODE IS UNAVAILABLE");
AddProductCode();
}
else {
AddProduct2nd();
}
}
The List#contains(Object) compares the given object with each element of the list using the equals() method. The String#equals() method checks equality by taking the case into consideration.
So, for that you can manually implement the logic.
Replace the boolean check = productcode.contains(code); with
boolean check = false;
for (String e: productcode) {
if (e.equalsIgnoreCase(code)) {
check = true;
break;
}
}
Now, check will be true if code is present in productcode irrespective of the case. If check is false this means that code is not present in productcode

Alternate way for nested ifs using Boolean in Java

I have below block of code
if(Objects.nonNull(isMine)) {
if (isMine) {
this.books= // gets it from the database;
} else {
this. books= // gets it from the database
}
} else {
this. books = // gets it from the database
}
isMine - is a Boolean object
I tried with switch case by converting isMine to a string as below
String.valueOf(isMine)
But didn't work .Suggest a better and faster way to implement above code in java.
You can flatten your if-else statement by using else if:
if(isMine == null) {
books = allList;
} else if(isMine) {
books = myList;
} else {
books = notMyList;
}
Another approach would be to sperate the checks into methods:
public List<Book> getBookList(Boolean isMine) {
return isMine == null ? allList : getBookList(isMine.booleanValue());
}
public List<Book> getBookList(boolean isMine) {
return isMine ? myList : notMyList;
}
You can use Optional in this case:
Boolean isMine = null;
String str = "";
Optional<Boolean> optional = Optional.ofNullable(isMine);
str = optional.map(i -> i ? "a" : "b").orElse("c");
System.out.println(str);
So it will be something like:
this.books = optional.map(i -> i ? valForTrue : valForFalse).orElse(valForNull);
this.books = isMine != null ? (isMine ? this.myList : this.notMyList) : this.allList;
Using ternary operator inside of ternary operator e.g.
Do not even think about performance in your case, that's tiny.
Your current way looks good. And you have an answer with flatten way and nested ternary too.
If you still want to learn how to use switch in this case (please do not put this code in production. posting for showing you a way)
Correct way to achieve using String.valueOf(isMine) is
switch ( String.valueOf(isMine) ) {
case "null":
//TODO
break;
case "true":
//TODO
break;
case "false":
//TODO
break;
}
With pattern matching provided by vavr.io it can get very clean:
List<Books> output = Match(input).of(
Case($(true), dbCallX()),
Case($(false), dbCallY()),
Case($(), dbCallZ()));

How to NOT find something in JAVA?

EDIT :
ok, sorry for not so clear question. Let's try other way:
We have an ArayList of names : Peter, John, Adam
We are looking for String name;
If ArrayList contains the String, we want to write the String. If ArrayList doesn't contains the String, we want to add the String into the ArrayList.
If I'm looking for "Adam", then this program is not working, because first it finds name "Peter", then "John", and only after that it finds "Adam". So for the first 2 times, it thinks, "Adam" is not in the list, and acts so.
String findName;
for (i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getValue().contains(findName)) {
System.out.println(findName);
break;
}
else
arrayList.add(findString);
}
Original question :
I have a String and an Array (ArrayList). I have to do something, if the String is in the Array and something else, if it is not in the Array. How do I do that?
I can't do it like this :
String myString;
for (i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getValue().equals(myString)) {
DO SOMETHING;
break;
}
else
DO SOMETHING ELSE;
}
because it will find the String only once and all the other times it will act, like the arraylist doesn't contains the String.
So I'm doing it like this :
String findString = "0";
String myString;
for (i = 0; i < arrayList.size(); i++) {
if (arrayList.get(i).getValue().equals(myString)) {
DO SOMETHING;
findString = "2"; //when I find the String, I change this
break;
}
if findString == "0"; //if I have not found the String, this happens
DO SOMETHING ELSE;
}
and I have the feeling, it should be not done like this. ;)
I know I can use booleans instead of this way, but it's the same in other way. Isn't there total different way of doing this correctly?
Cleanest way is as follows: Declare a method which returns whether the string is in the array:
public boolean arrContainsStr(String str, String[] arr) {
for (int i = 0; i < arr.length; i++) {
if (arr[i].equals(str)) {
return true;
}
}
return false;
}
Then use this method in your code like this:
String myString;
String[] myArray;
if (arrContainsStr(myString, myArray)) {
DO SOMETHING;
}else {
DO SOMETHING ELSE;
}
This is for primitive string arrays. Note that if you are using an ArrayList or similar, you can simply use the .contains(myString) method to check if the list contains your string. Documentation here: https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#contains(java.lang.Object)
This question is a bit odd, but just reading your first sentence, if you want to see if a List e.g. ArrayList contains an object (e.g. a String) you can just use the contains(Object o) method rather than looping through. I must be missing your point. In any case, an example:
String stringToFind = "Foo";
List<String> stringList = new ArrayList<>();
stringList.add("Foo");
if (stringList.contains(stringToFind)) {
System.out.println("String found");
} else {
System.out.println("String not found");
}
Output: String found. (In this example).
Couldn't you use .contains as below to check if the String is in the list?
if(arrayList.contains(myString)){
// DO SOMETHING
} else {
// DO SOMETHING ELSE
}
You could set a boolean to true if you find your value then break.
If you don't find the value, the boolean will stay to false.
Then you do the if
Its a little vague so I'm not sure if this is what you want, but if you remove the break in the first segment of code i think you will get what you want. do you want it do DO SOMETHING for every occurrence of the string or just the first one. also if you do need the break you could check the value of i after the loop terminates so
if(i==arrayList.size())
{
//String found
}
else
{
//String not found
}

Variable might not have been initialized when dealing with array

In a method I created I am trying to create is meant to return an array of user inputted strings. The issue that I am having it the compiler is saying that userData may not be initialized at userData[i]=tempData; and at return userData;. I am unsure why this error is occuring, and would like some feedback.
public String[] getStringObj() {
int i = 0;
String tempData;
String[] userData;
Boolean exitLoop = false;
System.out.println("Please list your values below, separating each item using the return key. To exit the input process please type in ! as your item.");
do {
tempData = IO.readString();
if (tempData.equals("!")) {
exitLoop=true;
} else {
userData[i] = tempData;
i++;
}
} while (exitLoop == false);
return userData;
}
In the interests of improving code quality:
You don't need that exitLoop flag; just do
while(true) {
String input = IO.readString();
if(input.equals("!")) {
break;
}
/* rest of code */
}
Since you seem like you want to just add stuff to an array without bounds, use an ArrayList instead of an array (added bonus, this gets rid of i too):
List<String> userData = new ArrayList<String>();
...
userData.add(line);
If you do these two things, your code will be much more concise and easy to follow.
Your userData is not initilaized and you are attempting to use it here userData[i]=tempData; before initialization.
Initialize it as
String[] userData = new String[20];
//20 is the size of array that I specified, you can specify yours
Also in your while condition you can have while(!exitLoop) instead of while(exitLoop==false)
You didn't initialize the String[]. Just do String[] userData = new String[length]. If you are unsure of the length, you may just want to use an ArrayList<String>.

Is there a way to shorten a conditional that contains a bunch of boolean comparisons?

e.g
if("viewCategoryTree".equals(actionDetail)
|| "fromCut".equals(actionDetail)
|| "fromPaste".equals(actionDetail)
|| ("viewVendorCategory".equals(actionDetail))&&"viewCategoryTree".equals(vendorCategoryListForm.getActionOrigin())
|| ("viewVendorCategory".equals(actionDetail))&&"fromEdit".equals(vendorCategoryListForm.getActionOrigin())
|| "deleteSelectedItem".equals(actionDetail)
|| ("viewVendorCategory".equals(actionDetail))&&"fromLink".equals(vendorCategoryListForm.getActionOrigin())){
//do smth
}
I've tried something like this
if(check("deleteSelectedItem,viewCategoryTree,fromCut,fromPaste,{viewVendorCategory&&viewVendorCategory},{viewVendorCategory&&fromEdit},{viewVendorCategory&&fromLink}",actionDetail,actionOrigin)){
//do smth
}
public boolean check(String str, String ad, String ao){
String oneCmp = "";
String[] result = str.split(",");
ArrayList adList = new ArrayList();
ArrayList aoList = new ArrayList();
for (int i=0; i<result.length; i++){
oneCmp = result[i];
Matcher m = Pattern.compile("\\{([^}]*)\\}").matcher(oneCmp);
if(m.matches()){
m.find();
String agrp = m.group();
String[] groupresult = agrp.split("[\\W&&[^!]]+");
Boolean a = false;
Boolean b = false;
if(groupresult[0].startsWith("!")){
a = !groupresult[0].substring(1).equals(ad);
} else a = groupresult[0].equals(ad);
if(groupresult[1].startsWith("!")){
b = !groupresult[1].substring(1).equals(ao);
}else b = groupresult[1].equals(ao);
if(agrp.indexOf("&&")!=-1){
if(!(a && b))return false;
}
else if(agrp.indexOf("||")!=-1){
if(!(a || b))return false;
}
} else {
if(oneCmp.indexOf("^")==-1){
checklist(oneCmp,ad);
if(!checklist(oneCmp,ad))return false;
}else{
if(!checklist(oneCmp,ao))return false;
}
}
}
return false;
}
public boolean checklist(String str, String key){
if(str.startsWith("!")){
if(str.substring(1).equals(key))return false;
}else { if (!str.substring(1).equals(key)) return false;
}
}
return false;
}
is there a better way to do this ? thanks.
Move the check to a method that takes actionDetail as argument:
// Assumes vendorCategoryListForm is a member variable.
boolean check(String actionDetail) {
return ("viewCategoryTree".equals(actionDetail)
|| "fromCut".equals(actionDetail)
|| "fromPaste".equals(actionDetail)
|| (("viewVendorCategory".equals(actionDetail))
&&"viewCategoryTree".equals(vendorCategoryListForm.getActionOrigin()))
|| (("viewVendorCategory".equals(actionDetail))
&&"fromEdit".equals(vendorCategoryListForm.getActionOrigin()))
|| "deleteSelectedItem".equals(actionDetail)
|| (("viewVendorCategory".equals(actionDetail))
&&"fromLink".equals(vendorCategoryListForm.getActionOrigin())))
}
if (check(actionDetail)) {
// do this
}
How about creating an array of what you need to test against.
And then some code like this:
arrayOfStrings = ["viewCategoryTree", ...]
match = false
for elem in arrayOfStrings:
if elem == actionDetail:
match = true
break
The good thing about an array is that it is easily extensible: you can easily add/remove elements to it both statically and dynamically.
Also kindly look at this post
Language Agnostic Credits to Galwegian
See Flattening Arrow Code for help.
1. Replace conditions with guard clauses.
2. Decompose conditional blocks into seperate functions.
3. Convert negative checks into positive checks.
Honestly, that code is no more readable. I would better suggest to encapsulate that conditional check into some property for the type like if (control.IsApplicable) { // do smth }.
No matter either you parameterize by one or two arguments.
But I suppose better solution is to have an array of matches that could be tested against and if matched then return true.
I don't think you are going to improve on this without adding a bunch of complexity, both in terms of the notation that you use to express the conditions and the implementation of the "engine" that evaluates them.
The notation issue is that: while you may end up expressing the conditions in fewer characters, someone else reading your code has to figure out what that funky string literal really means.
Besides, anything clever you do could have an impact on performance. For instance, your attempt compiles and applies a regex multiple times for each call to check.
Stick with what you've got would be my advice.
if(isValidActionDetail(actionDetail)
|| (isValidActionDetail(actionDetail)
&& ("viewCategoryTree".equals(vendorCategoryListForm.getActionOrigin())
|| "fromEdit".equals(vendorCategoryListForm.getActionOrigin())
|| "fromLink".equals(vendorCategoryListForm.getActionOrigin())))){
//do smth
}
}
public static boolean isValidActionDetail (String actionDetail) {
return "viewCategoryTree".equals(actionDetail) || "fromCut".equals(actionDetail)
|| "fromPaste".equals(actionDetail) || "deleteSelectedItem".equals(actionDetail)
|| "viewVendorCategory".equals(actionDetail);
}
You can decompose in the above way, as the first step to refactoring your logic.

Categories

Resources