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.
Related
I finally think I found a way to sort my transactions by amount using the if statement but I need a way to indicate when one transaction is less or greater than the other they exchange places.
I have a sample of what I've done so far and not too sure what I am missing out here.
#Override
public int compareTo(Student_Transaction Tra)
{
if (getAmount() == ((Student_Transaction) Tra).getAmount()) {
return Amount - Tra.getAmount();
}
else if (getAmount() > ((Student_Transaction) Tra).getAmount()) {
return 1;
}
else if (getAmount() < ((Student_Transaction) Tra).getAmount()) {
return -1;
}
return Amount;
}
This is compareTo method of Student_Stransaction, so no need to use getters:
#Override
public int compareTo(Student_Transaction Tra) {
return Tra != null ? Float.compare(amount, Tra.amount)) : 1;
}
I'd suggest you go with:
return Double.compare(this.amount, tra.getAmount());
which means, you can avoid having to do all those if/else if conditions.
I literally realised that what I did in the thread above was the answer to my question, it clearly defined how I will sort my amounts in each transaction object the final fold of this stage was to use the collection.sort method and in one of the recent threads I have posted the answer to how it is done...
#Override
public int compareTo(Student_Transaction Tra){
if (Tra.getAmount() < getAmount()) {
return -1;
}
else if (Tra.getAmount() == getAmount()) {
return 0;
}
else {
return 1; // Tra.getAmount() > getAmount()
}
}
I didn't need to go the extra mile, ya boy just is misunderstood with his programming and I'm much appreciated with have this community of professional programmers dedicating their time to help people like me out :)
I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}
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!
I need to convert the code below to a recursive method without using global variables and using only one parameter.I Searched the topics already there is no code with one parameter and doesnt use the global variables.
public boolean isPrime(int x){
for(int i=2;i<x;i++)
if(x%i==0) return false ;
return true;
}
Ok, as for your requirements:
Without using global variables.
Using only one parameter.
And, based on:
it come up in one of my university exams
There a couple of aspects to take into account:
If you pass an instance of a Class you are passing only one variable, and as Classes can have multiple variables inside...
They do not state if you can call multiple functions inside, so, again, this is a hint or clue, of what can you do. So, two solutions for you:
Solution 1 (Using Classes)
class RecursVar {
int x;
int i = 2;
RecursVar(int x) {
this.x = x;
}
}
public boolean isPrimeRecurs(int x){
return isPrime(new RecursVar(x));
}
boolean isPrime(RecursVar recursVar) {
if(recursVar.x % recursVar.i == 0)
return false;
if (++recursVar.i >= recursVar.x)
return true;
return isPrime(recursVar);
}
Solution 2 (Cleaner approach without using Classes but based in that the function that can have only one parameter is isPrime )
boolean isPrime(int x) {
return checkForPrime(x, 2);
}
boolean checkForPrime(int x, int i) {
if (i >= x) return true;
if (x % i == 0) return false;
return checkForPrime(x, ++i);
}
Again, this solutions are based on that many exams require a little creativity and maybe that was the aim of this case.
This cases should not be used in production, they are slow and
prune to make honor to this site (StackOverFlow) with a sweet
java.lang.StackOverflowError
It's an interesting problem.
If you can use java 8, you can solve the problem as followed (note that the case isPrime(2) needs to be checked with an additional if condition):
package test;
import java.util.function.Function;
public class Test {
public static void main(String[] args) {
System.out.println(isPrime(13));
}
private static Function<Integer, Boolean> fun;
public static boolean isPrime(int x) {
fun = i -> {
if (i > 2) return (x%i != 0) && fun.apply(i-1);
else return (x%i != 0);
};
return fun.apply(x-1);
}
}
One of my schoolmates' topic accually recieve a solution here it is if you interested its quite brilliant
https://stackoverflow.com/questions/35660562/finding-prime-numbers-recursively-with-using-only-one-parameter?noredirect=1#comment59001671_35660562
I'd like to call a method that either returns false, or an integer. At the moment my code is:
int winningID = -1;
if((ID = isThereAWinner()) != -1) {
// use the winner's ID
} else {
// there's no winner, do something else
}
private int isThereAWinner() {
// if a winner is found
return winnersID;
// else
return -1;
}
I don't like the if((ID = isThereAWinner()) != -1) bit as it doesn't read very well, but unlike C you can't represent booleans as integers in Java. Is there a better way to do this?
I would use something similar to Mat's answer:
class Result {
public static Result withWinner(int winner) {
return new Result(winner);
}
public static Result withoutWinner() {
return new Result(NO_WINNER);
}
private static final int NO_WINNER = -1;
private int winnerId;
private Result(int id) {
winnerId = id;
}
private int getWinnerId() {
return winnerId;
}
private boolean hasWinner() {
return winnerId != NO_WINNER;
}
}
This class hides the implementation details of how you actually represent if there were no winner at all.
Then in your winner finding method:
private Result isThereAWinner() {
// if a winner is found
return Result.withWinner(winnersID);
// else
return Result.withoutWinner();
}
And in your calling method:
Result result = isThereAWinner();
if(result.hasWinner()) {
int id = result.getWinnerId();
} else {
// do something else
}
It may seem a little bit too complex, but this approach is more flexible if there would be other result options in the future.
What about something like:
private int getWinnerId() {
// return winner id or -1
}
private boolean isValidId(int id) {
return id != -1; // or whatever
}
int winnerId = getWinnerId();
if (isValidId(winnerId)) {
...
} else {
...
}
This is all quite subjective of course, but you usually expect an isFoo method to provide only a yes/no "answer".
The problem is you are trying to return two values at once. The approach you have taken is the simplest for this. If you want a more OO or design pattern approach I would use a listener pattern.
interface WinnerListener {
void onWinner(Int winnerId);
void noWinner();
}
checkWinner(new WinnerListener() {
// handle either action
});
private void checkWinner(WinnerListener wl) {
// if a winner is found
wl.onWinner(winnersID);
// else
wl.noWinner();
}
This approach works well with complex events like multiple arguments and multiple varied events. e.g. You could have multiple winners, or other types of events.
I'm afraid not. To avoid errors caused by mistaking if(a == b) for if(a = b), Java removes the conversion between boolean type and number types. Maybe you can try exceptions instead, but I think exception is somewhat more troublesome. (My English is not quite good. I wonder if I've made it clear...)
Perhaps you may wish to consider exceptions to help you with your understanding of asthetics of coding.
Use Integer instead of int and return null instead of -1. Look from this point: "I am returning not integer, but some object that represents winner identity. No winner - no instance"
Joe another suggestion, this is constructed based on #Mat and #buc mentioned little while ago, again this is all subjective of course I'm not sure what the rest of your class/logic is. You could introduce an enum with different ResultStatuses if it makes sense within the context of your code/exmaple.
As Matt mentioned you would expect isValid method to return a boolean yes/no (some may also complain of readability)
public enum ResultStatus {
WINNER, OTHER, UNLUCKY
}
This could be an overkill as well and depends on the rest of your logic (and if logic is expanding) but I thought I'll suggest nonetheless my two cents! So therefore in your public class (similar to #bloc suggested) you could have a method such as below that will return the status of the result checked.
public ResultStatus getResultStatus() {
if (isWinner()) {
return ResultStatus.WINNER;
} else {
return isOtherCheck() ? ResultStatus.OTHER : ResultStatus.UNLUCKY;
}
}