I have an String arraylist. Lets say
private final List<String> fruits = new ArrayList<String>();
Now I have to compare an incoming line against the items in the arraylist
while ((line = in.readLine()) != null) {
if (!(line.equals(fruits.get(0)) || line.contains(fruits.get(1)) ||
line.contains(fruits.get(2)) || line.contains(fruits.get(3)) ||
line.contains(fruits.get(4)) || line.contains(fruits.get(5)) ||
line.contains(fruits.get(6)) || line.equals(fruits.get(7) || line.equals(fruits.get(8)))) {
// "DO SOMETHING"
}
}
I have to match the string exactly for some cases and just use contains for some cases. But at last I should not have more than 3 conditions in my if clause.
Since you want to use either equals() or contains() on each fruit in the list and your fruits are ever growing, consider turning your list into a map, where you store the desired method by fruit.
private enum Method {
CONTAINS,
EQUALS;
}
#Test
public void testFruits() throws IOException {
Map<String, Method> methodByFruit = new HashMap<>();
methodByFruit.put("apple", Method.CONTAINS);
methodByFruit.put("pear", Method.CONTAINS);
methodByFruit.put("grenade apple", Method.CONTAINS);
methodByFruit.put("banana", Method.EQUALS);
methodByFruit.put("kiwi", Method.EQUALS);
BufferedReader in = new BufferedReader(new StringReader("kiwi2"));
String line;
while ((line = in.readLine()) != null) {
boolean success = false;
for (Entry<String, Method> entry : methodByFruit.entrySet()) {
String fruit = entry.getKey();
Method method = entry.getValue();
if (method == Method.EQUALS) {
success = line.equals(fruit);
} else {
success = line.contains(fruit);
}
if (success) {
break;
}
}
if (!success) {
System.out.println("DO SOMETHING");
}
}
}
Your requirement is not clear. Whether the equality check is specifically for index 7 or 8 only or what. But anyway here is my suggestion. you can make a simple method to check if line contains subset from the list
public boolean isFound(List<String> f, String l){
for(int i=0;i<f.size();i++){
if(l.contains(f.get(i)){
return true;
}
}
return false;
}
Then you can check it like this:
if(isFound(fruits, line) || fruits.contains(line)){
//Do Something
}
Related
I have created the following method which returns a Triple of strings. However, I don't like the way I've written it because I think I've put in too many Npe checks making it unreadable.
private Triplet<String, String, String> getInfoFromTable(Person person) {
StringBuilder idWithText = new StringBuilder();
String idText;
Date time = null;
Level level;
Exercise exerciseRecord = getExercise(person);
if (exerciseRecord != null && exerciseRecord.getId() != null) {
if(exerciseRecord.getLevel1() != null && exerciseRecord.getLevel2() != null){
level = new Level(exerciseRecord.getLevel1(), exerciseRecord.getLevel2());
} else {
level = new Level("1", "1");
}
idText = getIdText(level, exerciseRecord.getId());
if(!Strings.isNullOrEmpty(idText)) {
idWithText = idWithText.append(exerciseRecord.getId()).append(" " + idText);
}
if (exerciseRecord.getTime() != null) {
time = exerciseRecord.getTime().toDate();
}
return new Triplet<>(idWithText.toString(), "1", formatTime(time));
}
return new Triplet<>("", "", "");
}
Ηow can I make the above code look simpler? I've seen a little use of Optional but I don't know if it's good to use them in my case. Could someone help with the method refactor?
You need to split the huge method into several simple, it will decrease complexity.
private Triplet<String, String, String> getInfoFromTable(Person person) {
Exercise exerciseRecord = getExercise(person);
if (exerciseRecord != null && exerciseRecord.getId() != null) {
return new Triplet<>(getIdWithText(exerciseRecord, getLevel(exerciseRecord)), "1", formatTime(exerciseRecord.getTime()));
}
return new Triplet<>("", "", "");
}
private String formatTime(LocalTime time) {
if (time == null) {
return "";
}
return formatTime(time.toDate());
}
private Level getLevel(Exercise exerciseRecord) {
Level level;
if(exerciseRecord.getLevel1() != null && exerciseRecord.getLevel2() != null){
level = new Level(exerciseRecord.getLevel1(), exerciseRecord.getLevel2());
} else {
level = new Level("1", "1");
}
return level;
}
private String getIdWithText(Exercise exerciseRecord, Level level) {
String idWithText = "";
String idText = getIdText(level, exerciseRecord.getId());
if(!Strings.isNullOrEmpty(idText)) {
idWithText = String.format("%s %s", exerciseRecord.getId(), idText);
}
return idWithText;
}
I have lots of multiple if-else statements. For code optimization, I need to write one function for all if else logic. As of now my code structure is in below.
input request is in JSONObject(org.json.simple.JSONObject), which have more than 10 values.
String s = (String) inputObj.get("test");
String s1 = (String) inputObj.get("test");
String s2 = (String) inputObj.get("test");
String s3 = (String) inputObj.get("test");
if (s != null && s.trim().isEmpty()) {
if (s1 != null && s1.trim().isEmpty()) {
if (s2 != null && s2.trim().isEmpty()) {
if (s3 != null && s3.trim().isEmpty()) {
if (s4 != null && s4.trim().isEmpty()) {
........
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
return;
}
How to avoid this kind of looping and throw an error message in common method.
Advance thanks.
Consider adding all your strings to array or ArrayList of string, and looping thru each entry in it, and check them for null or emptiness.
You can try this.
void main() {
List<String> sList = new ArrayList<>();
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
for(String s : sList){
try {
checkString(s);
}catch (Exception e){
//log or print the exception, however you like
}
}
}
void checkString(String s) throws Exception{
if(s!= null && !s.trim().isEmpty()){
//doStuff
}else{
throw new Exception("String is null or empty !!!");
}
}
You should also check this out.
public class YourClass{
private boolean isBlankDataPresent(JSONObject inputObj, String[] keys) throws Exception {
for (String key : keys) {
String input = (String) inputObj.get(key);
if( input == null || input.trim().isEmpty())
throw new Exception(key +" is Empty");
}
return false;
}
public boolean validateData(JSONObject inputObj, String[] keys) throws Exception {
boolean isBlankDataPresent= isBlankDataPresent(inputObj, keys);
if (!isBlankDataPresent) {
// do Your Stuff and return true
}
}
}
public Integer checkIsEmapty(String checkingString){
if(checkingString != null && !checkingString.trim().isEmpty()){
return 1;
}
return 0;
}
public String method(){
String s ="";
String s1 = "hi";
String s2 = "java";
String s3 = null;
String s4 = null;
Integer s1i = checkIsEmapty(s);
Integer s2i = checkIsEmapty(s1);
Integer s3i = checkIsEmapty(s2);
Integer s4i = checkIsEmapty(s3);
Integer s5i = checkIsEmapty(s4);
Integer total = s1i + s2i + s3i + s4i + s5i;
switch (total){
case 1 :
// To DO
case 2 :
// To DO
}
}
in switch used to checking the value, U can pass binary and Integer also
Like #Emre Acre mentioned,
List<String> sList = new ArrayList<>();
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
boolean allDataValid = sList
.stream()
.allMatch(s -> s != null && s.trim().isEmpty());
if(allDataValid) {
......
} else {
return;
}
I have two foreach loops. One of them contains list of unique emails (outer). I would like to have that as outer loop and increase count by one every time there is a match between an element of outer loop and the inner loop.
My code now:
outer: for (String email : emailsOfContactsWhoFitDynConFilter) {
for (Contact contact : emailClicks.items) {
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
count++;
break outer;
} else if (queryStringActivity == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break outer;
}
}
}
}
It works, but problem is these two lines:
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
Are executed too many times which consumes a lot of time.
I could reverse the loops, so it would look like this:
outer: for (Contact contact : emailClicks.items) {
String[] contactLink = (contact.link).split("\\?", -1);
String queryStringActivity = getQueryStringByName("elqTrackId", contactLink[1]);
for (String email : emailsOfContactsWhoFitDynConFilter) {
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (queryStringActivity !=null && queryStringDynConLink!=null && queryStringActivity.equals(queryStringDynConLink)){
count++;
break outer;
} else if (queryStringActivity == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break outer;
}
}
}
}
That would be much faster, but my count++ would happen more times than I want, it wouldn't be +1 per unique email.
There are a couple good options here, but the first would be to simply cache the String[]. This is a valuable lesson in why you should use methods instead of members.
I suggest having a method of contact.getLinkCache() method, implemented something like I have below. This gives you the benefit of not splitting over and over again (there is a clone in there to protect the data, but clone is a pretty fast method, and unless you've identified this as being too slow, you should probably go with this.
class Contact {
String link;
String[] linkSplitCache;
public void setLink(String link) {
this.link = link;
this.linkSplitCache = null;
}
public String getLink() {
return link;
}
public String[] getLinkCache() {
if(linkSplitCache == null) {
linkSplitCache = link.split("\\?",-1);
}
// return linkSplitCache; // could corrupt!
return linkSplitCache.clone(); // pretty fast array copy
}
}
If it is too slow, then you would want some kind of map to cache it in, and this would probably be outside the Contact class.
Map<Contact, String[]> linkSplitCache = new HashMap<>();
outer: for (Contact contact : emailClicks.items) {
String[] contactLink = linkSplitCache.get(contact);
if(contactLink == null) {
contactLink = (contact.link).split("\\?", -1);
linkSplitCache.put(contact,contactLink);
}
// rest of loop here
With a great help from #corsiKlause Ho Ho Ho I could come to the solution:
Map<String, String[]> linkSplitCache = new HashMap<>();
int count = 0;
String[] linkInDynamicContentSplit = linkInDynamicContent.split("\\?", -1);
String queryStringDynConLink = getQueryStringByName("elqTrackId", linkInDynamicContentSplit[1]);
if (emailClicks != null && emailsOfContactsWhoFitDynConFilter != null) {
for (String email : emailsOfContactsWhoFitDynConFilter) {
inner: for (Contact contact : emailClicks.items) {
String[] contactLink = linkSplitCache.get(contact.EmailAddress);
if (contactLink == null){
contactLink = (contact.link).split("\\?", -1);
contactLink[1] = getQueryStringByName("elqTrackId", contactLink[1]);
linkSplitCache.put(contact.EmailAddress, contactLink);
}
if (email.equals(contact.EmailAddress) && contactLink[0].equals(linkInDynamicContentSplit[0])) {
if (contactLink[1] !=null && queryStringDynConLink!=null && contactLink[1].equals(queryStringDynConLink)){
count++;
break inner; // this excludes link clicks which were done
// twice by the same person
} else if (contactLink[1] == null || queryStringDynConLink == null) {
System.out.println(" - Missing elqTrackId. But base the same, count++");
count++;
break inner;
}
}
}
}
}
Basically what I did was adding the link into the HashMap with the unique key Email address, which makes sure that I don't do the same operation more than once where it's not necessary.
Basically I just want an error message when there are no more records to show in the array list. What do I need to tweak?
public void nextRecord()
{
if(records.size() > 0)
{
recordCount++;
if(records.get(recordCount) != null)
{
String[] array = records.get(recordCount).split(",");
String item = array[0].trim().replaceAll("\"", "");
String number = array[1].trim();
String cost = array[2].trim();
String amnt = array[3].trim();
txtItem.setText(item);
txtNumber.setText(number);
txtCost.setText(cost);
txtAmount.setText(amnt);
}
}
else if (records.get(recordCount) == null)
{
JOptionPane.showMessa
Check the size of arrayList before calling get() like,
if(recordCount< records.size() && records.get(recordCount) != null)
{
//Do the processing
} else {
JOptionPane.showMessa
}
I need some help with designing the logic of my problem.
Model Bean
package com.ashish.model;
public class Model {
public Integer a,b,c,d;
public String f,g,h,i,j;
}
Service Class
package com.ashish.service;
import com.ashish.model.Model;
public class Service {
public StringBuilder query = null;
public Service(){
query = new StringBuilder("Select * from A where ");
}
public String build(Model m){
if(m.a != null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("a="+m.a);
if(m.a == null&&m.b!=null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("b="+m.b);
if(m.a == null&&m.b==null&&m.c!=null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("c="+m.c);
if(m.a == null&&m.b==null&&m.c==null&&m.d!=null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("d="+m.d);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e!=null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("e="+m.e);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f!=null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("f="+m.f);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g!=null&&m.h==null&&m.i==null&&m.j==null)
query.append("g="+m.g);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h!=null&&m.i==null&&m.j==null)
query.append("h="+m.h);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i!=null&&m.j==null)
query.append("i="+m.i);
if(m.a == null&&m.b==null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j!=null)
query.append("j="+m.j);
if(m.a != null&&m.b!=null&&m.c==null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("a="+m.a);query.append(" b="+m.b);
if(m.a != null&&m.b==null&&m.c!=null&&m.d==null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("a="+m.a);query.append(" c="+m.c);
if(m.a != null&&m.b==null&&m.c==null&&m.d!=null&m.e==null&&m.f==null&&m.g==null&&m.h==null&&m.i==null&&m.j==null)
query.append("a="+m.a);query.append(" d="+m.d);
// ... 512 lines in this pattern
return query.toString();
return query.toString();
}
}
I want to write public String build(Model m) in such a way so that I would not have to write 512 if-else condition.
Conditions:
All instance variables of Model class can have two value ( null, not null)
They all can be null or they all can be not null.
There would be total 512 combinations ( since every instance variable have two state and there are 9 instance variable so total number of condition would be 2^9 )
Order of the instance variable does not matter.
My project use Java 6 so I can not use switch on String.
I have looked into various pattern but none of them is meeting my requirement.
Thanks for looking
A private helper method as follows should do it -
private void appendIfNotNull(String fieldOp, String val) {
if(val != null) {
query.append(fieldOp).append(val);
}
}
Then just call it in the build method -
public String build(Model m) {
appendIfNotNull("a=", m.a); //no null check, just need to repeat this for all fields
Maybe you want to try to use Java Reflection to read all fields of your Model and read them. You don't need to know the field name to read it. So it would be fully dynamic and generic, even if you extend your Model class.
Class modelClass = Class.forName(Model.class.getName());
Field[] fields = circleClass.getFields(); //includes all fields declared in you model class
for (Field f : fields) {
System.out.println("field " + f.getName() + " has value: " + f.get(<YOUR_MODEL_INSTANCE>));
}
Example code adapted from:
- http://forgetfulprogrammer.wordpress.com/2011/06/13/java-reflection-class-getfields-and-class-getdeclaredfields/
Will this code make sense?
interface ToStringer {
void appendTo(StringBuilder sb);
}
class NullToStringer implements ToStringer {
public void appendTo(StringBuilder sb) {
// Do nothing
}
}
class IntegerToStringer implements ToStringer {
private String fieldName;
private Integer val;
public IntegerToStringer(String fieldName, Integer val) {
this.fieldName = fieldName;
this.val = val;
}
public void appendTo(StringBuilder sb) {
sb.append(field).append(" = ").append(val);
}
}
public class ToStringFactory {
public ToStringer getToStringer(String fieldName, Integer val) {
if (val == null) {
return new NullToStringer();
} else {
return new IntegerToStringer(fieldName, val);
}
}
public ToStringer getToStringer(String fieldName, String val) {
...
}
}
public String build(Model m){
ArrayList<ToStringInstance> list = ...;
list.add(ToStringFactory.getToStringer("f", m.f));
list.add(ToStringFactory.getToStringer("g", m.g));
list.add(ToStringFactory.getToStringer("h", m.h));
StringBuilder sb = ...;
for (ToStringInstance tsi : list) {
tsi.appendTo(sb);
}
return sb.toString();
}
I am not sure what logic you are trying to implement, but the general approach: creating interface, concrete implementaion of printing values, using NullValue pattern to hide null problem and using factory to control objects creation should do the trick.
By using this approach you can avoid problems with 2^9 combinations by avoiding multiple if-else statements.
Update. Just came to my mind. You can use reflection. Iterate through all fields, get value of each, print it if it is no null. Maybe this will be enough.
It seems like you want to append to the query for each element that is not null. This can be done quite simply with an auxiliary method or two:
public class Service {
public StringBuilder query = null;
public Service(){
query = new StringBuilder("Select * from A where ");
}
public String build(Model m) {
boolean added = first;
first &= !maybeAdd("a", m.a, first);
first &= !maybeAdd("b", m.b, first);
. . . // all the rest of the fields of m
}
/**
* Add an equality test to an SQL query if the value is not {#code null}.
* #param key the field name for the query
* #param value the value to test for equality
* #param first flag indicating that no conditions have been added
* #return {#code true} if the value was appended; {#code false} otherwise.
*/
private boolean maybeAdd(String key, Object value, boolean first) {
if (value != null) {
if (!first) {
query.append(" AND ");
}
query.append(key).append('=').append(value);
return true;
}
return false;
}
}
Note that if all fields of the model are null, your query will not be correctly formed. You might want to include the appropriate logic in the maybeAdd method to compensate for that.
As I mentioned in my comment, you don't need a different if for every combination. You just need to append the values that are not null, and ignore the ones that are. Let me know if this works for you.
public String build(Model m) {
// use this to know when to add " AND " to separate existing values
boolean appended = false;
if (m.a != null) {
query.append("a=" + m.a);
appended = true;
}
if (m.b != null) {
if (appended) {
query.append(" AND ");
}
query.append("b=" + m.b);
appended = true;
}
if (m.c != null) {
if (appended) {
query.append(" AND ");
}
query.append("c=" + m.c);
appended = true;
}
if (m.d != null) {
if (appended) {
query.append(" AND ");
}
query.append("d=" + m.d);
appended = true;
}
if (m.e != null) {
if (appended) {
query.append(" AND ");
}
query.append("e=" + m.e);
appended = true;
}
if (m.f != null) {
if (appended) {
query.append(" AND ");
}
query.append("f=" + m.f);
appended = true;
}
if (m.g != null) {
if (appended) {
query.append(" AND ");
}
query.append("g=" + m.g);
appended = true;
}
if (m.h != null) {
if (appended) {
query.append(" AND ");
}
query.append("h=" + m.h);
appended = true;
}
if (m.i != null) {
if (appended) {
query.append(" AND ");
}
query.append("i=" + m.i);
appended = true;
}
if (m.j != null) {
if (appended) {
query.append(" AND ");
}
query.append("j=" + m.j);
appended = true;
}
return query.toString();
}
I don't know why you need two if statements for this:
if( m.a == null) {
query.append("m=null");
} else {
query.append("m="+m.a);
}
if( m.b == null) {
query.append("m=null");
} else {
query.append("m="+m.b);
}