How to write switch statements based on 3 variables? [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 8 years ago.
Improve this question
I have a lecagy validator class that I'd like to work with. It gives all permutations to validate 1-3 different fields.
class Validator {
Checker Validator.A, Validator.B, Validator.C;
Checker[] ABC = {Validator.A, Validator.B, Validator.C};
Checker[] AB = {Validator.A, Validator.B};
Checker[] BC = {Validator.B, Validator.C};
Checker[] AC = {Validator.A, Validator.C};
}
I don't have any influence on this class. But have to use one of these Checkers.
I want to chose the needed validator based on the fields that are not empty.
Therefore, I wrote the following switch statemend. But to me it seems to be very ugly. How could I improve this?
String a, b, c;
boolean isA = !a.isEmpty();
boolean isB = !b.isEmpty();
boolean isC = !c.isEmpty();
Checker[] checker;
if (isA && isB && isC) {
checker = Validator.ABC;
} else if (isA && isB) {
checker = Validator.AB;
} else if (isA && isC) {
checker = Validator.AC;
} else if (isB && isC) {
checker = Validator.BC;
} else if (isA) {
checker = Validator.A;
} else if (isB) {
checker = Validator.B;
} else if (isC) {
checker = Validator.C;
}

How about this?
List<Checker> checkers = new ArrayList<Checker>();
if (!a.isEmpty()) checkers.add(Validator.A);
if (!b.isEmpty()) checkers.add(Validator.B);
if (!c.isEmpty()) checkers.add(Validator.C);
Checker[] checker = checkers.toArray(new Checker[checkers.size()]);

Alternatively you could do it this way
List<Checker> list = new ArrayList<>();
if (!a.isEmpty()) {
list.add(Validator.A);
}
if (!b.isEmpty()) {
list.add(Validator.B);
}
if (!c.isEmpty()) {
list.add(Validator.C);
}
Checker[] checker = list.toArray(new Checker[list.size()]);

You could simplify it using reflection, approximately like this (haven't actually compiled, but should be close enough):
String name = (a? "A":"") + (b? "B":"") + (c? "C":"");
checker = Validator.class.getField(name).get();

if you really want to do it, you have to convert whole your input to "case'able" data. e.g int
2 ^((int) a) * 3^((int) b) * 5^((int) c)
or to string (since java 7)
but, don't do it. it's ugly. create a collection and fill it with necessary checkers. as showed by Chris King

You can do the whole thing with enums. It adds a powerful extendibility component.
enum Checker {
A, B, C;
public boolean check () {
// You do this.
return true;
}
}
enum Validator{
ABC(Checker.A, Checker.B, Checker.C),
AB(Checker.A, Checker.B),
BC(Checker.B, Checker.C),
AC(Checker.A, Checker.C),
A(Checker.A),
B(Checker.B),
C(Checker.C),
;
final Checker[] checkers;
Validator(Checker ... checkers) {
this.checkers = checkers;
}
boolean validate(Collection a, Collection b, Collection c) {
// Grow the name of the validator from the data.
String name = (!a.isEmpty()?"A":"") +
(!b.isEmpty()?"B":"") +
(!c.isEmpty()?"C":"");
// The final result.
boolean checksOut = true;
// TODO: Handle the all-empty scenario.
if ( name.length() > 0 ) {
// Pull the checks array out of the correct validator.
Checker [] checks = Validator.valueOf(name).checkers;
for ( Checker check : checks ) {
// Do all of the checks defined.
checksOut &= check.check();
}
}
return checksOut;
}
}

Related

Many else if statements in the code [closed]

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 4 years ago.
Improve this question
I would like to ask if it is a good way to have many else if statements based on the boolean conditions like below?
public void borrowItem() throws IOException {
boolean ableToBorrow = isUserAbleToBorrow(cardID);
boolean isDemand = checkDemand(title, authorNumber);
boolean userExists = checkIfUserExists(cardID);
if(ableToBorrow && isDemand && userExists) {
//lots of code....
}else if(!ableToBorrow && isDemand && userExists) {
System.out.println("User limit exceeded");
}else if(!ableToBorrow && !isDemand && userExists) {
System.out.println("User limit exceeded and no book demand");
}else if(ableToBorrow && !isDemand && userExists) {
System.out.println("No book demand");
}else if(ableToBorrow && !isDemand && !userExists) {
System.out.println("No book demand and user does not exists");
}else if(ableToBorrow && isDemand && !userExists) {
System.out.println("Unrecognized user!");
}
}
Is it a good way or there is a better idea in java to do that?
I agree with what GhostCat wrote. It's way too procedural. One way (probably the best way in this case) to implement polymorphism would be the decorator pattern.
Define your interface:
public interface User {
void borrowItem(String item);
String cardId();
}
Create the base implementation:
public final class SimpleUser implements User {
private final String cardId;
public SimpleUser(final String cardId) {
this.cardId = cardId;
}
#Override
public void borrowItem(final String item) {
// Borrowing logic.
}
#Override
public String cardId() {
return cardId;
}
}
And then add decorators for each validation you need. E.g. to check if user exists:
public final class ExistingUser implements User {
private final User origin;
public ExistingUser(final User origin) {
this.origin = origin;
}
#Override
public void borrowItem(final String item) {
if (!exists(cardId())) {
throw new IllegalStateException("Unrecognized user!");
}
origin.borrowItem(item);
}
#Override
public String cardId() {
return origin.cardId();
}
private boolean exists(String cardId) {
// Check if exists...
}
}
And combine them. This way, when you need one additional validation, you add one additional decorator. With ifs, the number of cases would grow geometrically.
new ExistingUser(
new DemandAwareUser(
new SafelyBorrowingUser(
new SimpleUser(cardId)
)
)
).borrowItem(item);
It is very bad style: hard to read and understand, easy to mess up when you are asked to enhance/change behavior. Please note that such code is also extremely hard to test - as you would want to make sure to cover all possible paths that flow can take within such a metho.
The typical answer to such things is to use polymorphism, like having a base class defining some interface, and specific child classes each implementing the interface differently.
In that sense: your code is a clear violation of Tell Don't Ask: you code queries some status from somewhere, to then make decisions on that. Instead, you create classes/objects and tell them to do the right thing (again: that is where polymorphism kicks in).
Nothing wrong with the way it is, but there are other options if you want your code to be more concise. If I change you error messages very slightly, I can write it this way:
if(ableToBorrow && isDemand && userExists) {
//lots of code....
} else {
String errorMsg = "";
if (!ableToBorrow) errorMsg += "User limit exceeded - ";
if (!isDemand) errorMsg += "No book demand - ";
if (!userExists) errorMsg += "Unrecognized user!"
System.out.println(errorMsg);
}
There is also the option of bundling the boolean's into a single integer value. This obfuscates what your code is doing though, and I personally wouldn't use unless you wanted to create an enum to keep track of what the integer values meant;
int status = 4*(ableToBorrow?1:0)+2*(isDemand?1:0)+(userExists?1:0);
switch(status){
case 7: //lots of code....
break;
case 3: System.out.println("User limit exceeded");
break;
//etc...
}

How to check whether two expressions are equivalent or not in java [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I want to check whether two expressions are equivalent or not in Java. Let's say I have two expressions:
exp 1:
A && B && ( C || D)
exp 2:
B && ( C || D ) && A
I want to check whether these two expressions are equivalent or not.
What i mean by equivalent was if say we have two expressions then these two expressions must have same tokens(A , B, C, D) and the same relational operators between them. And should return the same values for all inputs. I do not want to consider the order how java execute these things. And what i need is a library or some java code snippet for doing so. Information about an algorithm is also fine.
They are not due to the short evaluation. In Java, A && B returns false immediately when A is evaluated to false. It makes a difference e.g. when it comes to Exceptions or boolean methods that are not pure functions.
You can try the following experiment:
public class Test {
public n = 0;
public boolean A() {
System.out.println("A");
return false;
}
public boolean B() {
System.out.println("B");
return true;
}
public boolean C() {
n++;
return true;
}
public boolean D() {
n = n*2;
return false;
}
public static void main(String[] args) {
Test test = new Test();
if (test.A() && test.B()) { System.out.println("true"); }
if (test.B() && test.A()) { System.out.println("true"); }
if (test.C() && test.D()){}
else {System.out.println(t.n);}
t.n = 0;
if (test.D() && test.C()){}
else {System.out.println(t.n);}
t.n = 0;
boolean c = test.C();
boolean d = test.D();
if (d && c){}
else {System.out.println(t.n);}
}
}
It shows the consequences of a short evaluation connected with side effect.

How work java lambda? I can not understand [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I have started to learn Java lambda and I do not understand it. I found an example.
String[] atp = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka", "David Ferrer", "Roger Federer", "Andy Murray", "Tomas Berdych", "Juan Martin Del Potro"};
players.forEach((player) -> System.out.print(player + "; "));
And it works fine, but my code does not work.
public class Counter {
String[] atp = {"Rafael Nadal", "Novak Djokovic", "Stanislas Wawrinka", "David Ferrer", "Roger Federer", "Andy Murray", "Tomas Berdych", "Juan Martin Del Potro"};
List<String> players = Arrays.asList(atp);
private int a = 7;
private int b = 7;
public int summ(int a, int b) {
return a + b;
}
public void print(){
players.forEach((player) -> System.out.print(player + "; "));
summ((a,b)-> System.out.print(a + b));
}
}
I want understand how lambda works.
This is not working -
summ((a,b)-> System.out.print(a + b));
You can use lambdas with functional interfaces.
What is a functional interface?
It is basically an interface that has one and only abstract method (but can have other default methods for example)
The most frequent example is the Predicate interface.
public interface Predicate <T> {
boolean test(T t);
// Other methods
}
This one take any Object (generics) and returns a boolean primitive.
So let's say we want to test a condition using this interface to find pair numbers in a loop, we code the following.
Predicate<Integer> function = a -> a%2 == 0;
for (int i = 0 ; i < 10 ; i++){
if (function.test(i)){ // The primitive is AutoBoxed into an Integer Object here
System.out.println(i);
}
}

Dynamic calculation over dataset by providing logic externally [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am doing some mathematical operation on a data set. As per the requirement of the project, the mathematical formula/logic can be changed at any time. So I am thinking to keep these formals out from the Java code, may be in config file. Below is the sample config file-
formula.properties file-
formula_a=(a+b)/(7*c+b^2)
formula_b=(a^(1/2)-formula_a*13)
formula_c=spilt_time(formula_b,a,b)
Calculator.java (A dummy Java file, which may not be correct as Its for demo purpose only)
public class Calculator
{
private final static String FORMULA_A = "formula_a";
private final static String FORMULA_B = "formula_b";
private final static String FORMULA_C = "formula_c";
public static void main(String[] args)
{
long a = 1738342634L;
long b = 273562347895L;
long c = 89346755249L;
long ansFromFormulaA = applyFormulaFromConfig(FORMULA_A, new long[] { a, b, c });
long ansFromFormulaB = applyFormulaFromConfig(FORMULA_B, new long[] { a, b, c });
long ansFromFormulaC = applyFormulaFromConfig(FORMULA_C, new long[] { a, b });
}
// spilt_time is used in formula_c
public static long[] spilt_time(long[] params)
{
final long[] split = new long[2];
// Some logic here which is applied on params array and answer is pushed
// into split array
return split;
}
private static long applyFormulaFromConfig(String formulaName, long[] params)
{
long ans = 0L;
// Read formula from property file here and apply the params over it and
// return the answer
return ans;
}
}
Please help me to design a solution for this.
Ok here is one:
Define your functions in JavaScript in a separate js-file outside your application. Might look like this:
function myFunction1(x, y, z) {
return x * y + z;
}
Now you can evaluate these script via the Java ScriptEngine and call those functions by name, passing them your params.
Have a look: http://www.wondee.info/2013/10/30/the-scriptengine-bindings/
edit:
Propeterties file:
function1=x + y * z
function2=x * x
read the functions into formula variable... and...
You can put your functions in a String and put it inside a function body like that:
String formula = readFromProperties("function1");
String myFunctionScript = String.format("function myFunction(x, y, z) { return %s ;}", formula);

Finding the range in which a number lies [closed]

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 6 years ago.
Improve this question
I have the following method:
private static final int OPEN_FOR_RAISE_RANGE = 35;
private static final int OPEN_FOR_CALL_RANGE = 25;
public void foo(double num){
if(num <= OPEN_FOR_RAISE_RANGE){
//do something
}
else if(num <= (OPEN_FOR_RAISE_RANGE + OPEN_FOR_CALL_RANGE)){
//do something else
}
//etc
}
which basically checks what range the number falls in and acts appropriately. I was wondering if there is a nicer/more efficient way to do this other than lots of if's?
Thanks
Check out NumberRange from commons-lang.
NumberRange range = new NumberRange(
OPEN_FOR_RAISE_RANGE,
OPEN_FOR_RAISE_RANGE + OPEN_FOR_CALL_RANGE
);
if(range.containsNumber(num)) {
// do this
} else {
// do something else
}
That's about as good as it gets I think.
Note the compiler will replace the OPEN_FOR_RAISE_RANGE + OPEN_FOR_CALL_RANGE calculation with the value 60 at compile time so you're not computing this on every call.
Seems fine by me, it'd be more worrysome if the if-statements were nested like this:
if (...) {
if (...) ...;
else (...) { ... }
if (...)
if (...)
if (...) ...;
else (...) ...;
}
Then you really should consider breaking the code out to their own methods.
If you had an enormous number of if/ifelse/ifelse/.../else statements, something like this might help:
public interface Choice {
public boolean check(int value);
public void action(int value);
}
public class BelowRange implements Choice {
public static boolean check(int value) {
return (value < 10);
}
public void action(int value) {
// Do something;
}
}
public class Range1 implements Choice {
public boolean check(int value) {
return (value > 10 && value < 50);
}
public void action(int value) {
// Do something;
}
}
...
And in your code:
List<Choice> choices = new ArrayList<Choice>();
choices.add(new BelowRange());
choices.add(new Range1());
...
for (Choice choice : choices) {
if (choice.check(value)) {
choice.action(value);
}
}
I might implement it so the implementations of choice could be static methods, instead of having to instantiate them, but the gist of the thing is there.
If the compiler heavily optimizes this, especially with a static method, it shouldn't be slower at all, and it would make an enormously nested if/else structure a lot more maintainable from a developer's point of view.

Categories

Resources