Change multiple if statements to avoid same code - java

I have the following code on a huge project. I want to find a better implementation to avoid the same code
if(CConst.CONST1.equals(SOMETHING1)){
const1fieldsaver = true;
if(a != 0){
//same code
if(value <= 0){
const1field = ...//same code
}
}
if(CConst.CONST2.equals(SOMETHING2)){
const2fieldsaver = true;
if(a != 0){
//same code
if(value <= 0){
const2field = ...//same code
}
}
how can i avoid these to if statements? The have the same code but as you can see it save the values to different variables. Is there any more efficient way to implement this?

I would suggest creating a method that you call inside each if block that executes the code you want.
if(CConst.CONST1.equals(SOMETHING1)){
const1fieldsaver = true;
if(a != 0){
executeSameCode(); //calling method here
if(value <= 0){
const1field = ...executeSameCode2(); //calling method, note that it is different from above method.
}
}
if(CConst.CONST2.equals(SOMETHING2)){
const2fieldsaver = true;
if(a != 0){
executeSameCode();
if(value <= 0){
const2field = ...executeSameCode2();
}
}
//somewhere else inside the class
public void executeMethod() {
//your code
} //can be made to return stuff
public void executeMethod2() {
//your code
} //again, can be made to return stuff
This way, you don't need to set up lots of temporary variables, but instead, just call the method from wherever you want.
Hope that helped!

If possible,
assign conditions directly to booleans and merge If-Statements.
e.g.
const1fieldsaver = CConst.CONST1.equals(SOMETHING1);
if(const1fieldsaver && a != 0 && value <= 0) {
const1field = ...
}
For more complex conditions I would use functions as recommended by Ted Lyngmo.

Related

Is it possible in java to simplify the following if-statement?

I want to simplify this if-Statement and prevent writing "!='*'" three times. Is it possible?
if (i != '*' && j != '*' && k != '*')
use arrays:put all elements into the array, traverse the array and judge。
List<String> list = new LinkedList<>(Arrays.asList(i,j,k));
if(list.stream().noneMatch("*"::equals)){
}else{
}
use string: splice elements into a string
String temp = i+j+k;
if(temp.contains("*")){
}
I want to simplify this if-Statement and prevent writing "!='*'" three times.
Here is a solution that simplifies the readability and intent.
First, make a simple, obvious method with a clear name (bonus: this is easy to write unit tests around):
private static boolean isValid(char i) {
return i != '*';
}
Then in your calling code, do this:
if (isValid(i) && isValid(j) && isValid(k)) {
// do things if all are valid
}
You can further improve the readability by making a single method which checks isValid() for an array of characters:
private static boolean allAreValid(char[] chars) {
for (char ch : chars) {
if (!isValid(ch)) {
return false;
}
}
return true;
}
Then your calling code becomes really clear, not just the steps but also the intent – proceed with the body of the if statement only if the characters are all valid.
char[] chars = {i, j, k};
if (allAreValid(chars)) {
// do things if all are valid
}
Yes it is possible to omit writing !='*' three times but the method will be still longer one. I would suggest to use the method which you have written in your question but if you really want to try something other out (maybe out of curiosity), you can do this:
char ch[] = {i,j,k}; /*I hope the variables i,j,k in question are char type*/
boolean flag = false;
for(int t = 0; t < ch.length; t++){
if(ch[t] != '*')
flag = true;
else{
flag = false;
break;
}
}
if(flag){
//Tasks to do...
}
Writing this much is a tedious job. Thus, if (i != '*' && j != '*' && k != '*') is the most optimised one. So I would recommend using it.

Java 8 short circuit many consecutive methods that return a boolean value

I'm looking for an elegant way to short circuit many consecutive methods that return a boolean value.
Ex See below for an example. Can this be streamed or implemented using lambdas?
public boolean outerMethod() {
if(booleanMethod1() && booleanMethod2() && booleanMethod3() && ...) {
// Do work
} else {
// Do something else
}
}
My favorite refactor if my list of condition1 && condition2 && ... && conditionN grows too long is usually
boolean theMeaningOfANDingAllConditions = condition1
&& condition2
&& ...
&& conditionN;
if (theMeaningOfANDingAllConditions) {
// Do work
} else {
// Do something else
}
I don't think "short circuit" is the word you're looking for. That has a specific meaning.
If what you want to do is combine your conditions into a shorter line, combining them into a function is a common pattern.
if (allBooleanMethods()) {
// Do work
} else {
// Do something else
}
...
private boolean allBooleanMethods() {
boolean result = booleanMethod1();
result = result && booleanMethod2();
result = result && booleanMethod3();
return result;
}
Well, you could, of course, achieve it with streams:
boolean result = Stream.<Supplier<Boolean>>of(
() -> a(),
() -> b(),
() -> c()
)
.allMatch(Supplier::get);
but indeed the question is if it'll make it more elegant. I don't think so.
I would stick with the &&:
boolean result =
aMethodName() &&
anotherMethodName() &&
yetAnotherMethodName() &&
moreOfThem...
if (result) {
...
}
else {
....
}

Java TreeSet not adding object

I am trying to add objects into a Treeset but the objects not all are getting added.
class Fruits
{
String name ;
int weight;
int price;
Fruits(String n, int w, int p)
{
this.name=n;
this.weight=w;
this.price =p;
}
#Override
public int hashCode() {
System.out.println("hashcode called");
int prime =31;
int result =1;
result = prime*result +(this.name.hashCode()+this.price+this.weight);
return result;
}
#Override
public boolean equals(Object obj) {
System.out.println("Equals called");
if(null!=obj)
{
Fruits f= (Fruits) obj;
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
{
return true;
}
}
return false;
}
}
class FruitsComparator implements Comparator<Fruits>
{
//Order by Name, then quanity and then Price
#Override
public int compare(Fruits f1, Fruits f2)
{
if(f1.name.equals(f2.name) && f1.weight == f2.weight && f1.price == f2.price)
{
System.out.println(1);
return 0;
}
else if(f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price < f2.price)
{
System.out.println(2);
return -1;
}
else if (f1.name.equals(f2.name) && f1.weight==f2.weight && f1.price > f2.price)
{
System.out.println(3);
return 1;
}
else if (f1.name.equals(f2.name) && f1.weight<f2.weight && f1.price == f2.price)
{
System.out.println(4);
return -1;
}
else if (f1.name.equals(f2.name) && f1.weight>f2.weight && f1.price == f2.price)
{
System.out.println(5);
return 1;
}
else if (f1.name.compareTo(f2.name) <1 && f1.weight==f2.weight && f1.price == f2.price)
{
System.out.println(6);
return -1;
}
else if (f1.name.compareTo(f2.name) >1 && f1.weight==f2.weight && f1.price == f2.price)
{
System.out.println(7);
return 1;
}
return 0;
}
}
From public static void main of another class.
Fruits f1= new Fruits("Apple",1,3);
Fruits f2= new Fruits("Apple",10,1);
Fruits f3= new Fruits("Apple",15,2);
Set<Fruits> sf = new TreeSet<Fruits>(new FruitsComparator());
sf.add(f1);
sf.add(f2);
sf.add(f3);
System.out.println("--Fruits Example--");
for( Fruits f: sf)
{
System.out.println(f.name+"-"+f.weight+"-"+f.price);
}
The output I get is :
--Fruits Example--
Apple-1-3
But when I have fruits objs as below i get the all the objects
just keeping everything same but the third element.
Fruits f1= new Fruits("Apple",1,3);
Fruits f2= new Fruits("Apple",1,1);
Fruits f3= new Fruits("Apple",1,2);
The output get for this is
--Fruits Example--
Apple-1-1
Apple-1-2
Apple-1-3
So somehow my objects are treated as same when I keep different elements on weight and price. I couldn't figure out as why the objects are treated as same. Please help.
The primary issue is, you are always checking two fields to be equal and only one to be different.
At the final else, that happens if at least 2 fields are different, you return 0 which means they should be treated as equal, and that is the reason you have this issue.
Since the order you want is to first sort by name, then by quantity and then by price, remove the && f1.price == f2.price from the 4th condition onwards, and remove && f1.weight==f2.weight on the last two.
You can avoid this issue completely if you use Java 8 style.
Set<Fruits> sf = new TreeSet<Fruits>(Comparator.comparing(Fruits::getName)
.thenComparing(Fruits::getWeight)
.thenComparing(Fruits::getPrice)
);
I have added the working code in codiva - online java compiler ide. I have also included a slightly cleaner implementation in FruitsComparator.java file.
Tree related collections don't use equals() or hashCode(). Those come into play for Map.
Your conditions in the compare result in a 0, hence the fruit isn't inserted.
First Apple goes in as the tree is empty. The 2nd & 3rd Apple result in false in all the if conditions, thus returning the final 0. Put a System.out.println() before the final return to confirm.
If you want to sort the fruits first by name, then by weight & then finally by price, here's a more compact way doing it:
#Override
public int compare(Fruits f1, Fruits f2) {
if (f1.name.equals(f2.name)) {
if (f1.weight < f2.weight) {
return -1;
} else if (f1.weight > f2.weight) {
return 1;
} else {
if (f1.price < f2.price) {
return -1;
} else if (f1.price > f2.price) {
return 1;
} else {
return 0;
}
}
} else {
return f1.name.compareTo(f2.name);
}
}
TreeSet, when used with a Comparator, the elements' equality is decided by the compare method of the Comparator, otherwise would use the compareTo method of its element since they are required to implement the Comparable interface. The hashcode and equals methods will only be used by the Set interface itself (such as method contains uses equals method to check if the elements are presented). And hashcode is not something that a TreeSet to use while it is used by HashSet which is totally another way to implement Set interface. Thus, in your code, since the compare method you've overridden of the Comparator treats these elements equal, so they cannot be inserted for multiple times. One guideline that the Java Tutorial points out is, the compare method should comply with the equals methods, which is, the elements should be treated equal in the compare method if and only if the equals method do.
And in your equals method, you did use this.weight == f.price to compare two fruits, which I don't think is what you intended to do. This makes your equals methods not consistent with the compare method.
For your reference, see Java Object Ordering tutorial, and as well as a question I asked two days ago.
You have an error in your equals method in class Fruits:
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.price)
should have been:
if(this.name.equals(f.name) && this.price==f.price && this.weight == f.weight)
(note the last part).

Compare one ArrayList and combine common elements

I've been working on an algorithm to loop through one ArrayList containing a custom object. I'm now on hour 20 and I've gotten almost nowhere.
ArrayList<TicketItem> all = new ArrayList<>();
// ... 'all' gets filled here ... //
ArrayList<TicketItem> allCopy = new ArrayList<>(all);
for (int i = allCopy.size() - 1; i > 0; i--) {
TicketItem last = allCopy.get(i);
for (int j = 0; j < all.size(); j++) {
TicketItem compare = all.get(j);
if (last.getInt(TicketItem.TICKET_ITEM_ID) != compare.getInt(TicketItem.TICKET_ITEM_ID)) {
if (last.canBeGrouped(compare)) {
last.put(TicketItem.TICKET_ITEM_NUMBER, compare.getInteger(TicketItem.TICKET_ITEM_NUMBER));
allCopy.set(i, last);
break;
}
}
}
}
This works when it wants to and to be honest, it's probably really ugly. I just can't get my head around a better option.
The important method inside TicketItem is this one:
public boolean canBeGrouped(TicketItem other) {
if (other == null)
return false;
if (getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (other.getBoolean(TicketItem.TICKET_ITEM_VOID))
return false;
if (getInteger(TicketItem.MENU_ITEM) == null)
return false;
if (getInteger(TicketItem.MENU_ITEM).equals(other.getInteger(TicketItem.MENU_ITEM))
&& getBigDecimal(TicketItem.TICKET_ITEM_TOTAL).compareTo(
other.getBigDecimal(TicketItem.TICKET_ITEM_TOTAL)) == 0) {
ArrayList<TicketItemModifier> mThis = getModifiers();
ArrayList<TicketItemModifier> mOther = other.getModifiers();
if (mThis == null && mOther == null)
return true;
if (mThis != null && mOther != null) {
if (mThis.size() == mOther.size()) {
for (int i = 0; i < mThis.size(); i++) {
TicketItemModifier m1 = mThis.get(i);
TicketItemModifier m2 = mOther.get(i);
Integer m1MenuModifierId = m1.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
Integer m2MenuModifierId = m2.getInteger(TicketItemModifier.MENU_MODIFIER_ID);
if (!(m1MenuModifierId != null && m2MenuModifierId != null && m1MenuModifierId
.equals(m2MenuModifierId))) {
return false;
}
}
return true;
}
}
}
return false;
}
Again, super ugly especially the for loop in there that works when it wants to. If need be I can modify hashCode and equals methods for both classes TicketItem and TicketItemModifier, however I would like to stay away from those two methods and do something along the lines of Comparable classes because just because they can be grouped does not mean they are equal.
What I want to do basically is go through one ArrayList filled with TicketItem objects and when two can be grouped I need to change the TicketItem object to match it.
I would suggest you create a new property or function like TickeItemCode which should be string concatenation of MENU_ITEM+ "-"+ TICKET_ITEM_TOTAL+ "-" + MENU_MODIFIER_IDs in modifiers list. you can filter the list to remove items where TICKET_ITEM_VOID is true and then sort by new property TickeItemCode and do grouping. This way you can reduce your time from n^2 to nlogn

Methods that return boolean values

Okay, so my question is regarding boolean returns. For my Comp Sci homework, I have to make a course registration program using methods, and one of them is an add course method. Basically, you search for the class in a catalog, and if it matches you add it to the students schedule and return a boolean value of true. I did this, but for some reason it is giving me an error. Here is the code:
public static boolean addCourse(
Course[] catalog,
Course[] mySchedule,
int myNumCourses,
int dept,
int courseNum)
{
int j;
int i;
int k;
int deptCat;
int courseNumCat;
Course courseAdd = null;
char checkDay;
int checkTime;
if (mySchedule.length == myNumCourses) {
return false;
}
for (i = 0 ; i < catalog.length ; i++) {
Course course = catalog[i];
deptCat = course.getDepartment();
courseNumCat = course.getCourseNumber();
if (deptCat == dept && courseNumCat == courseNum) {
courseAdd = catalog[i];
break;
}
else continue; }
for (j = 0 ; j < myNumCourses ; j++) {
if (mySchedule[j] == null) {
mySchedule[j] = courseAdd;
return true;
}
else continue;
}
for (k = 0 ; k < mySchedule.length ; k++) {
Course course = mySchedule[k];
if (course != null) {
checkDay = course.getDay();
checkTime = course.getPeriod();
if (checkDay == courseAdd.getDay() && checkTime == courseAdd.getPeriod()) {
return false;
}
}
else continue;
}
}
Why doesn't it recognize the boolean return values? Is it because I placed them inside a loop?
You need to place a return-statement at the end of your method, even if you might know it will never be reached (the compiler is not smart enough to know that, which explains the error).
For instance, even this will not compile:
public static boolean foo() {
if (true)
return true;
}
unless we add a final return statement. What you have is analogous.
There is nothing wrong with putting your return values in loops, however, the compiler sees no guarantee that this method will return a value and thus raises an error. At the very end of the method you need to return either true or false, whichever is most appropriate. All of your returns are within conditionals and therefor could fail to execute leaving your function with no return statement.
You must explicitly return a boolean(true/false) in ALL code path.Because your function's return type is "boolean".
In your case,you must add a return statement after the last loop.
If you don't want to write to many "return xx" statement,you can change the return type of this function to "void".And throw Exception in the false cases.
I think there is a problem with the last loop. If the condition for returning false is never met, it continues until it get to the end of the schedule, without returning anything. If you were to add a return at the end of the method this loop could fall through to it. Did you mean to return true after the loop, if no 'return false' is executed?
for (k = 0; k < mySchedule.length; k++) {
Course course = mySchedule[k];
if (course != null) {
checkDay = course.getDay();
checkTime = course.getPeriod();
if (checkDay == courseAdd.getDay()
&& checkTime == courseAdd.getPeriod()) {
return false;
}
} else
continue;
}
Where ever you are using if statement its possible else also must return or flow must go to another return.ELSE is missing with return.

Categories

Resources