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.
Related
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 4 months ago.
Improve this question
Basically need to create a class which is custom type that has two integers: -1 and 1, instead of all the integers that exist.
If you would suggest using enum (never implemented before), could you please suggest how would that work.
public class PlusOrMinusOne{
private int plusOne=1;
private int minusOne=-1;
}
Java does not let you write your own primitives, and does not have operator overloading. It is therefore simply impossible to have a class such that any expressions that are of that type act like a number. In other words, given:
PlusOrMinusOne a = ...;
int b = a + 1; // cannot be made to work
if (a == -1) // cannot be made to work
What you can do is simply create 2 instances such that they are the only instances of a given class. One of them is the value associated with +1, the other with -1. There is nothing specific about these 2 instances that reflects that they represent -1 or +1 - you can code them however you like.
enum is the general way to do this - it takes care of ensuring nobody can make instances other than the ones you defined, for example.
public enum PlusOrMinusOne /* horrible name, come up with a better one */ {
PLUS_ONE(+1),
MINUS_ONE(-1),
;
private final int value;
PlusOrMinusOne(int value) {
this.value = value;
}
public static PlusOrMinusOne of(int value) {
if (value == -1) return MINUS_ONE;
if (value == +1) return PLUS_ONE;
throw new IllegalArgumentException("" + value);
}
public int getValue() {
return value;
}
public PlusOrMinusOne neg() {
if (this == PLUS_ONE) return MINUS_ONE;
return PLUS_ONE;
}
public String toString() {
return this == PLUS_ONE ? "+1" : "-1";
}
}
When using enums you can define custom fields, so in your case you can do for example:
public enum CustomNumber {
PLUS_ONE(1),
MINUS_ONE(-1);
public final int value;
CustomNumber(int value) {
this.value = value;
}
}
public static void main(String[] args) {
System.out.println(CustomNumber.MINUS_ONE.value);
System.out.println(CustomNumber.PLUS_ONE.value);
}
enum PlusOrMinusOne {
PLUS_ONE(1),
MINUS_ONE(-1);
public final int num;
PlusOrMinusOne(int num) {
this.num = num;
}
}
public static void main(String[] args) {
System.out.println(CustomNumber.MINUS_ONE.num);
System.out.println(CustomNumber.PLUS_ONE.num);
}
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...
}
I am newbie to object orientated programming and trying to construct something which resembles a basic vote counter which should take an int parameter that represents a choice of two candidates and print the election results to the terminal window. albeit (the votes attributable to each candidate and the total votes cast)
The method I am looking for should also return a string that gives information on the success or failure of casting the vote.”your vote has been cast” “invalid choice, no vote cast"
I have created a class and the constructors and also implemented some basic get methods.
I am wondering how I should go about achieving this objective albeit through a conditional statement or using some sort of advanced method.
any help in terms of the syntax or wider approach would be appreciated.
public class VoteCounter {
private String candidate1;
private String candidate2;
private int candidate1Votes;
private int candidate2Votes;
private boolean completed;
public VoteCounter(String candidate1, String candidate2) {
this.candidate1 = candidate1;
this.candidate2 = candidate2;
this.candidate1Votes = 0;
this.candidate2Votes = 0;
this.completed = false;
}
public VoteCounter() {
this("CANDIDATE 1", "CANDIDATE 2");
}
public String getCandidate1 () {
return this.candidate1;
}
public String getCandidate2 () {
return this.candidate2;
}
public Boolean getCompleted () {
return this.completed;
}
public void setCompleted (boolean completed) {
this.completed = completed;
}
}
Something like this?
private String vote(int choice)
{
if(choice == 1)
{
candidate1Votes++;
}
else if(choice == 2)
{
candidate2Votes++;
}
else
{
return "invalid choice, no vote cast";
}
return "your vote has been cast";
}
I would do that in more general manner, avoiding code duplication and allowing to change number of candidates easily.
So let's make a class Vote similar to your VoteCounter but only for one candidate, with following fields:
private String candidate; // init this in constructor
private int candidateVotes; // initially 0, so no need to init
and with vote() method like in other answer but also without a candiadate, so:
public void vote() {
candidateVotes++;
}
Then you can make class VoteCounter which will take any number of candidates and will keep them in Array or Map.
Map<Integer, Vote> votes = new HashMap<>();
then you're creating vote method with choice:
public void vote(int choice) {
votes.get(choice).vote();
}
Then all is left is to iterate through your votes map and find the one with biggest number of votes.
I have read the similar question and learnt that it is not possible to use a ternary operation instead of if statement, which does not have else statement. Because, if-without else statements are binary not ternary. My question is more best-practice.
In my code, there are lots of code snippet like that
if( calculation < 1 ){
calculation= 0;
}
I would like to shorten these with tenary. Is it a good practice to change these statements with the following.
calculation = calculation < 1 ? 0 : calculation;
You could create a class (or classes) that would create a nice fluent API. Such that your line would be:
calculationTo = replace(calculationTo).with(0).when(calculationTo < 1)
In my opinion it doesn't read much better than a standard if statement, but it also depends on the conditions that you have.
Example implementation:
public class Replacer<T> {
private final T value;
private T replacementValue;
private Replacer(T value) {
this.value = value;
}
public static <V> Replacer<V> replace(V value) {
return new Replacer<V>(value);
}
public Replacer<T> with (T replacementValue) {
this.replacementValue = replacementValue;
return this;
}
public T when(boolean condition) {
if (condition) {
return replacementValue;
} else {
return value;
}
}
}
import static somepackage.Replacer.replace;
public class Main {
public static void main(String[] args) {
int calculationTo = 3;
calculationTo = replace(calculationTo).with(0).when(calculationTo < 1);
}
}
You might expand it or make condition a function so it can be used with lambda, etc. I would also make method with return object of different class (e.g. ReplacerWithValue) so that calling with twice in one chain would result in compilation error.
Since you're asking for a best practice, I'll point out something where you could do better and then I'll tell you why I like the ternary operator.
Let me rephrase you're code snippet:
if (calculatedValueAfterStep1 < 1) {
calculatedValueAfterStep2 = 0;
} else {
calculatedValueAfterStep2 = calculatedValueAfterStep1;
}
When you read your code and somebody asks you "what does 'calculation' represent?" then you cannot answer this question without asking for the line number. The meaning of "calculation" changes over the course of the program code. If you cannot explain what a variable means, you cannot give it a good name. This is why I like my Version better. There is a clear Definition of what meaning the variables "calculatedValueAfterStep1" and "calculatedValueAfterStep2" are. Yes, the names are bad. Change them to your domain accordingly.
Now when you look at the code, you'll notice that "calculatedValueAfterStep2" is not declared. So let's Change the code:
int calculatedValueAfterStep2 = -1;
if (calculatedValueAfterStep1 < 1) {
calculatedValueAfterStep2 = 0;
} else {
calculatedValueAfterStep2 = calculatedValueAfterStep1;
}
Now it gets ugly. The same person asking the earlier question will now ask "why is 'calculatedValueAfterStep2' initialized with '-1'?". So here comes the ternary operator:
int calculatedValueAfterStep2 = (calculatedValueAfterStep1 < 1) ? 0 : calculatedValueAfterStep2;
beautiful!
Lets say I have:
if (count <= instance.getFCount()) {
//do something and return String
} else if (count <= instance.getFSCount()) {
//do something and return String
} else if (count <= instance.getTCount()) {
//do something and return String
} else if (count <= instance.getOCount()) {
//do something and return String
}
I am thinking how can I replace this code into something more object oriented. The problem is that if I would have statement like this:
if (count <= 0) {
//do something and return String
} else if (count <= 1) {
//do something and return String
} else if (count <= 2) {
//do something and return String
} else if (count <= 3) {
//do something and return String
}
I could replace it with some factory pattern or enum based approach because my values 0, 1, 2, 3 would always be static. For e.g. I would create a map to hold the class against the number, then if my count is 0 I would know that I need to create an instance from the class which was mapped with zero and so on.
But now I am thinking if there is any way to be done if I don't have the static values in if condition, because for e.g. what is returned to this: instance.getOCount() might be different depending on the configuration.
Could you give me some thoughts how to achieve this?
When you have lots of different if else statements, you can employ a Strategy Pattern. This helps you create manageable code that conforms to the best practice.
I believe there's no need to replace such a simple logic with a design pattern, it's not justified. A switch would be an improvement (assuming count is an integer), but why create a bunch of classes? it'd be justified only if each one had additional, different behavior.
If you use a NavigableMap such as a TreeMap, the keys being your thresholds and values being Callables, you'll be able to retrieve the appropriate Callable and invoke it, all in a one-liner. The relevant method is NavigableMap#ceilingEntry.
final NavigableMap<Integer, Callable<String>> strats = new TreeMap<>();
...
return strats.ceilingEntry(val).getValue().call(args);
I don't think using patterns is the solution here...everything will be harder to read than your original code. But if you are sure, this is one option:
Lets say your instance belongs to a class User. Create an interface
public interface IDynamicAction<T> {
boolean select(T t);
String action(T t);
}
Make a list
List<IDynamicAction<User>> actions = new ArrayList<IDynamicAction<User>>();
actions.add(new IDynamicAction<User>() {
#Override
public boolean select(User instance) {
return count <= instance.getFSCount();
}
#Override
public String action(User t) {
System.out.println("count <= instance.getFSCount()");
return "count <= instance.getFSCount()";
}
});
actions.add(new IDynamicAction<User>() {
#Override
public boolean select(User instance) {
return count <= instance.getTCount();
}
#Override
public String action(User t) {
System.out.println("count <= instance.getTCount()");
return " count <= instance.getTCount()";
}
});
actions.add(new IDynamicAction<User>() {
#Override
public boolean select(User instance) {
return count <= instance.getOCount();
}
#Override
public String action(User t) {
System.out.println("count <= instance.getOCount()");
return " count <= instance.getOCount()";
}
});
And execute your code with
for(IDynamicAction<User> action : actions){
if(action.select(instance)){
String s = action.action(instance);
System.out.println(s);
break;
}
}
Notice the break, I'm assuming based in your code only one action can execute
If you don't need a return value you may use an abstract class instead of an interface and make the if(select) action(); a part of the AbstractDynamicAction class the code will be nicer
Java7 does not really help doing that kind of stuff. Closures would make this things easier on the eye...but IMHO, your original multiple IF is the way to go.