Java compare values, best way - java

I has a method like this
private boolean validGrade(final StringBuilder grade) {
boolean isValid = false;
String semester = "semester";
if ((grade.toString().contains("2o") && grade.toString().contains(semester))
|| (grade.toString().contains("4o") && grade.toString().contains(semester))
|| (grade.toString().contains("6o") && grade.toString().contains(semester))
|| (grade.toString().contains("8o") && grade.toString().contains(semester))) {
isValid = true;
}
}
And I want to replace it witn something like this:
private boolean doValidGradoAntComp(final StringBuilder grade) {
boolean isValid = false;
switch (grade.toString()) {
case "2o semester":
isValid = true;
break;
case "4o semester":
isValid = true;
break;
case "6o semester":
isValid = true;
break;
case "8o semester":
isValid = true;
break;
default:
break;
}
return isValid;
}
And my doubt is:
which one is better?
Both works in the same way?

Why not iterate over the possibilities?
private boolean validGrade(final StringBuilder grade) {
String gradeString = grade.toString();
return List.of("2o", "4o", "6o", "8o")
.stream()
.map(x -> x + " semester")
.collect(Collectors.toSet())
.contains(gradeString);
}
Alternatively, if you're not looking for exact matches, do:
private boolean validGrade(final StringBuilder grade) {
String gradeString = grade.toString();
return gradeString.contains("semester") && List.of("2o", "4o", "6o", "8o")
.stream()
.anyMatch(gradeString::contains);
}
Finally, if your set of matches is inflexible (will always be "2o", "4o", "6o", "8o"), then you can just use a regular expression:
private boolean validGrade(final StringBuilder grade) {
return grade.toString().matches("[2468]o semester"); //exact match
// return grade.toString().matches("[2468]o.*semester|semester.*[2468]o"); //loose match
// return grade.toString().matches(".*([2468]o.*semester|semester.*[2468]o).*"); //equivalent to contains
}

No both the approaches are different, In the first approach you are using contains to check two string existed in grade (For example 2o and semester in grade). But in the second approche you are checking grade is equal to 2o semester. I prefer collecting all those to list and use anyMatch
List<String> list = List.of("2o","4o","6o","8o");
if(list.stream().anyMatch(val->grade.contains(val) && grade.contains(semester))) {

Both serve the same purpose, but each has its differences and weaknesses and strengths.
If / else
Writing and reading difficulty (code is difficult to write because you need to include multivalued checks in one statement)
Your decision to choose is whether your code will be executed or not.
As with the switch, you can create a default statement if its value is not true (else).
Switch
Easy to write and read code.
You will always enter the switch block, if there is no case that matches the value you enter it will default.
You can only use char or int in cases.
You only have one condition, unlike if / else you can have several types of conditions.
Conclusion:
In performance issues the switch is usually faster but the differences are minimal.
If you have few cases to check I would use if/else, but in your case the code you showed is recommended to use the switch case for the number of checks that you do it in one block of code only.

Regex may be slower than if-else or switch. But in your case I would put more value on readability and use regex.
private boolean validGrade(final StringBuilder grade) {
return grade.toString().matches("(2o|4o|6o|8o) semester");
}

Related

How to use IndexOf to see if a string contain numbers

I need to use indexOf to find numbers inside a string, and it gives me the error:
Type mismatch: cannot convert from int to boolean.
public static boolean validPassword(String password) {
if(password.length() >= 8 ){
return true;
}
else if (password.indexOf("0")) {
return true;
}
return false;
}
Don't use index. You can use String.matches().
String str = "ksksks8ksksksksksks";
System.out.println(str.matches(".*\\d.*"));
Honestly though, if you can do it anyway you want, I would simply write a method as follows. Regular expressions are great for complicated patterns but they are also expensive in terms of processing.
public static boolean containsNumber(String str) {
boolean found = false;
for (char c : str.toCharArray()) {
if (Character.isDigit(c)) {
found = true;
break;
}
}
return found;
}
You could also modify the above and call it indexOf and iterate thru the characters using a regular for loop. Then returning either the location of the first digit or -1 just like the String version of indexOf().
And finally, for fun, you could use the Streams capability of Java 8+.
public static boolean containsNumber(String str) {
return str.chars().filter(Character::isDigit).count() > 0;
}

Reducing conditional operators efficiently

What I am trying to perform: I am trying to reduce the conditional operators, Since Sonar is giving a error for it
if (!parseBooleanFromString(response.getBuy().getHasEligibleAccounts()) &&
(!parseBooleanFromString(response.getSell().getHasEligibleAccounts()) &&
(!parseBooleanFromString(response.getExchange().getHasEligibleAccounts()) &&
(!parseBooleanFromString(response.getWorkplaceRetirement().getHasPlansEligibleForChangeContributions()) &&
(!parseBooleanFromString(response.getWorkplaceRetirement().getHasPlansEligibleForChangeInvestments())))))) {
//Success
} else {
//Failure
}
private boolean parseBooleanFromString(String mStr) {
return Boolean.parseBoolean(mStr);
}
What i have tried:
I am trying to put all the boolean values in a list and check
Is that the best way to do or is there a more efficient way
You can also move these conditions into different functions which internally calls other functions and returns single boolean result. This way there will only one function in above if condition which will internally evaluate and returns result.
Since you're checking if each statement is false, how about you keep a global integer in memory: private int product = 1;. Make a separate method where you calculate the product (replaces the string to boolean parser):
private void updateProduct(String mStr){
if (Boolean.parseBoolean(mStr)) //If true, condition should fail
product *= 0;
else
product *= 1;
}
In essence, you are not running 'if statement' but multiplying the boolean:
product = 1;
updateProduct(response.getBuy().getHasEligibleAccounts());
updateProduct(response.getSell().getHasEligibleAccounts());
//etc
if (product > 0){
//success
} else {
//failure
}
Explanation: If at any point a condition was true, the product will always be 0. The only instance where the product is > 0 is when all statements were false
Not sure what sonar complains about, but you have alot of redundant parenthesis and confusing negations. Using DeMorgans law, you can at least simplify to:
boolean b = parseBooleanFromString(response.getBuy().getHasEligibleAccounts())
|| parseBooleanFromString(response.getSell().getHasEligibleAccounts())
|| parseBooleanFromString(response.getExchange().getHasEligibleAccounts())
|| parseBooleanFromString(response.getWorkplaceRetirement().getHasPlansEligibleForChangeContributions())
|| parseBooleanFromString(
response.getWorkplaceRetirement().getHasPlansEligibleForChangeContributions());
if (!b) {
or if you perfer more java 8 syntax
Stream<Boolean> bools = Stream.of(parseBooleanFromString(response.getBuy().getHasEligibleAccounts()),
parseBooleanFromString(response.getSell().getHasEligibleAccounts()),
parseBooleanFromString(response.getExchange().getHasEligibleAccounts()),
parseBooleanFromString(response.getWorkplaceRetirement().getHasPlansEligibleForChangeContributions()),
parseBooleanFromString(response.getWorkplaceRetirement().getHasPlansEligibleForChangeContributions()));
boolean c = ! bools.anyMatch(e -> e);
if (!c) {
I would do something like this:
private boolean checkEligibility(LaunchPoints response) {
final String trueStr = "true";
if (trueStr.equals(response.getBuy().getHasEligibleAccounts())) return true;
if (trueStr.equals(response.getSell().getHasEligibleAccounts())) return true;
[...]
return false;
}
The idea is, skip the parsing boolean, just check for "true" and make your conditions more readable.

How do I return the switch statement inside a do while loop using an instance method?

public void select()
{
do
{
switch(info)
{
case'1':
case'a':
return System.out.println("Hello");
case'2':
case'b':
return selection = 'b';
default:
return System.out.println("Close");
}
}while(info != 'b');
}
So what would be the proper syntax and is this the even possible to do. New to Java
First, the loop is not needed, you can delete that. And you are using return statements wrongly. You cannot return
System.out.println();
Also, your method is declared to return void which means nothing. That means your return statement doesn't need anything else,just the word return.
return;
So my advice is that print the stuff first, and then return. And you should really read Java for Dummies, by Barry Burd.
1st of all you can't return anything from a void method, instead change it to char for example:
public char select () {
//read user input
char userInput = '1'; //change it as you wish or read from console
switch (userInput) {
case '1':
case 'a':
return 'a';
case '2':
case 'b':
return 'b';
//... and so on
default:
return '0'; //Or anything you want (but it MUST be a char (at least for my code, if you change it to String, you can return a word or well... a String)).
}
}
Then on main method (or the method which called select()) you add:
char selection;
selection = select();
System.out.println(selection);
If you want to add the switch into a loop (do-while as in your question), then you might want to do it this way on main method:
char selection;
do {
selection = select();
System.out.println(selection);
} while (selection != '0');
However I strongly recommend you to read Java Docs: Switch Statement and Returning a Value from a method which is actually what you're trying to achieve.
From second link you can confirm what I said before (on the 1st line of my answer and as some other users stated on comments)
Any method declared void doesn't return a value.

how to fill the method public boolean checkAnswer(String response)?

I need help to see what i am doing wrong here. The Instructions are:
use StringTokenizer on getAnswer ;
while it hasMoreTokens ;
check if response matches the nextToken ;
return true if it does ;
return false if none do.
This is what i have coded:
public boolean checkAnswer{
StringTokenizer str = new StringTokenizer(getAnswer());
while (str.hasMoreTokens()){
if(response.matches(str.nextToken())) return true;
}
return false;
}
Your code will be parsed as
public boolean checkAnswer {
StringTokenizer str = new StringTokenizer(getAnswer());
while (str.hasMoreTokens()) {
if(response.equals(str.nextToken())) return true;
}
if(!response.equals(str.nextToken()))return false;
}
Which is not what you need to do according to your specification (and probably is neither what you intended to do while you wrote it) and it neither returns a boolean on every branch (since Javac won't look if branches are exhaustive for non trivial cases.
You want to return false if none of the tokens equals response. This is the case if and only if your while loop exits. See also #Jack's answer.

evaluate boolean values in Java

I am trying to evaluate the following from a string
boolean value = evaluate("false || true && true && false || true");
I need to get a boolean value of true for this one.
Any ideas on how to solve this problem in the most efficient way?
String value = ("false || true && true && false || true");
boolean result = false;
for (String conj : value.split("\\|\\|")) {
boolean b = true;
for (String litteral : conj.split("&&"))
b &= Boolean.parseBoolean(litteral.trim());
result |= b;
}
System.out.println(result); // prints true
If the only operators are && and ||, then I think this will work:
static boolean eval(String str) {
String s = str.replaceAll("\\s|\\|\\|false|false\\|\\|", "");
return !s.contains("false") || s.contains("||true");
}
For more complicated expressions, I found this library just for that.
Don't know how efficient it is though.
You'll need a small boolean expressions grammar. A bit of recursive parsing should do the trick.
If you don't know how to write such a parser, you may use JavaCC or something similar.
there are parsergenerators available for which you can define a grammar.
But if you only got || and && as operators and true and false as values you can easily do this by yourself, by implmenting a very simple finite state machine:
1.) Split the string into the tokens
2.) parse the left most value by using Boolean.parseBoolean(token) and safe it's value in some instance variable (your state)
3.) combine your instance variable with the next boolean token using the given operator
4.) Repeat step3 until you finished through the whole string
This seems to work although i havent thorougly tested it :)
public class BooleanFSParser {
private boolean parse(String data) {
String[] tokens=data.split("\\s");
boolean state=Boolean.parseBoolean(tokens[0]);
for (int i=1;i<(tokens.length / 2) + 1;i=i+2){
if (tokens[i].equals("&&")){
state=state && Boolean.parseBoolean(tokens[i+1]);
}else{
state=state || Boolean.parseBoolean(tokens[i+1]);
}
}
return state;
}
public static void main(String[] args) {
BooleanFSParser parser = new BooleanFSParser();
boolean val = parser.parse("true && true || false");
System.out.println(String.valueOf(val));
}
}
thats should give you a cirrectly parsed value, but it will get a bit more complex if you allow brackets for example ;)
have fun and check here for the theory
Finite-state_machine

Categories