how can I make the following code better? - java

I want to make the following code better, but cannot get a good idea.
Is there any way to solve this?
I just create a Android project and use greenDAO greendao to create tables by Class.
for (Field field : fields) {
fieldName = field.getName();
// we don't need this.
if ("serialVersionUID".equals(fieldName)) {
continue;
}
type = field.getType();
// primary key, just auto increment.
if ("id".equals(fieldName)) {
entity.addIdProperty().autoincrement();
continue;
}
// other fields
/*
* this is the problem what I want to solve.
* I thought it's too bad to read and have a bad looking.
*/
if (type.equals(String.class)) {
entity.addStringProperty(fieldName);
}else if (type.equals(Integer.class)) {
entity.addIntProperty(fieldName);
}else if (type.equals(Double.class)) {
entity.addDoubleProperty(fieldName);
}else if (type.equals(Float.class)) {
entity.addFloatProperty(fieldName);
}else if (type.equals(Long.class)) {
entity.addLongProperty(fieldName);
}else if (type.equals(Byte.class)) {
entity.addByteProperty(fieldName);
}else if (type.equals(Short.class)) {
entity.addShortProperty(fieldName);
}else if (type.equals(Boolean.class)) {
entity.addBooleanProperty(fieldName);
}else if (type.equals(Character.class)) {
entity.addStringProperty(fieldName);
}else if (type.equals(Date.class)) {
entity.addDateProperty(fieldName);
}
}

Java 8 solution: create a static Map of "adder methods" where each possible property type will be associated with corresponding lambda:
static final Map<Class<?>, BiConsumer<Entity, String>> ADDERS = new IdentityHashMap<>();
{{
ADDERS.put(String.class, Entity::addStringProperty);
ADDERS.put(Integer.class, Entity::addIntegerProperty);
//...
}}
then, for each field:
ADDERS.get(type).accept(entity, field.getName());

Class objects can be compared using == rather than .equals because there is only ever one instance per class.
It is occasionally necessary to have a sequence of nested if statements like this to find the right Class object, and this obviously very ugly (see the source code for Arrays.deepToString for a real example of this).
There are other solutions involving Map, or switching on type.getSimpleName(), however I would personally stick to the simple solution even if it is long-winded.

You could use more reflection.
String typeStr = type.getSimpleName();
switch(typeStr) {
case "Integer": typeStr = "Int"; break;
case "Character": typeStr = "String"; break;
}
Method m = enttity.getClass().getMethod("add" + typeStr + "Property", String.class);
m.invoke(entity, fieldname);

Related

What is better to use just one method with switch or 4 different methods?

I have a object and i get some fields from it, i made a method with a switch statement, the idea was make it generic and just call this method through parameters but now I´m not sure.
The options are
private String getCode(Row row, String code) {
String result;
switch (code) {
case code1:
result = row.getString("constant1");
break;
case code2:
result = row.getString(constant2);
break;
case code3:
result = row.getString(constant3);
break;
case code4:
result = row.getString(constant4);
break;
default:
result = null;
}
return result;
}
or
private String getcode1(Row row){
return row.getString("constant1")
}
private String getcode1(Row row){
return row.getString("constant2")
}
private String getcode1(Row row){
return row.getString("constant3")
}
private String getcode1(Row row){
return row.getString("constant4")
}
I wand to use the better way, I´m a little confuse
The answer is neither of the them.
What you have here is a value conversion process. How this works? Well, as far I understand, you need to store the data in form of key-value pair where key must be unique. So this is the definition of a HashMap in java.
Also, because you are using Switch I'm assuming that you can identify your data with some unique key. This meas for each code there is only one constant. But how we can apply this to my issue? Well, I think you have a collection of data from where you extracted a single row. Now, from this row you want to access to a value (lets call it codeValue) using a constant, but to get this constant you need a code. Like this: code->constant->codeValue
How can I implement this??
Well, we gonna need a HasMap() called constants, which defines its keys a codes and the values as constants. Now you easily get each constant if you know its code. Obviously, if you get the constant you can also get the codeValue of each `row, like this:
public class TestClass {
public static void main(String[] args) {
// Create a HashMap object called constants
Map<String, String> constants = new HashMap<String, String>();
// Add keys and values (code, constant)
constants.put("code1", "constant1");
constants.put("code2", "constant2");
constants.put("code3", "constant3");
constants.put("code4", "constant4");
System.out.println(constants);
Row row = loadRow();
String code = loadCode();
//How to use it
String result = getCodeValue(row, code);
System.out.println(result);
}
// Now you get the code from the Map
private String getCodeValue(Row row, String code) {
return row.getString(constants.get(code));
}
}
In case your input code is different than constant, I will suggest the following approach. Create an Enum mapping code and constant.
public enum Mapping {
MAPPING_FIRST("code1", "constant1"),
MAPPING_SECOND("code2", "constant2");
private String code;
private String constant;
// constructor and getters
public static Mapping getMappingFromCode(String code){
return Arrays.stream(Mapping.values())
.filter(mapping -> mapping.getCode().equals(code))
.findFirst()
.orElse(null);
}
}
Now, create a method to access value from row.
private String getValue(Row row, String code) {
Mapping mapping = Mapping.getMappingFromCode(code);
if(mapping == null){
return null;
}
return row.getString(mapping.getConstant());
}
This question is little bit to much, but I will try to explain best I could. For me second option is no no at all. Why? You are making methods that you will have to sort out with some if/else statements anyway, for example:
if (code.equals(code1))
someString = getcode1(row);
else if (code.equals(code2))
somestring = getcode2(row);
else if (code.equals(code3))
someString = getcode3(row);
else
someString = getcode4(row);
Why not use this:
if (code.equals(code1))
someString = row.getString("content1");
else if (code.equals(code2))
somestring = row.getString("content2");
else if (code.equals(code3))
someString = row.getString("content3");
else
someString = row.getString("content4");
The first one I can see being used, but there is alternative there. Give us entire minimal requirement code with entire class and methods and we could help you far more than using these snippets of code.
Create an enum for mapping of code and constant. In that enum, create a generic method where you can get code just passing through parameter.
public enum MyEnum {
CODE1("constant1"), CODE2("constant2");
private String constant;
public String getConstant() {
return constant;
}
private MyEnum(String constant) {
this.constant = constant;
}
private static String getConstant(String code) {
return Arrays.stream(MyEnum.values()).filter(mapping -> mapping.name().equalsIgnoreCase(code))
.map(e -> e.getConstant()).findAny().orElse(null);
}
public static String getCode(Row row, String code) {
String constant = getConstant(code);
return constant != null ? row.get(constant) : null;
}
}
You can get code from row object by calling genric method getCode().
MyEnum.getCode(row, "code1")

Alternate way for nested ifs using Boolean in Java

I have below block of code
if(Objects.nonNull(isMine)) {
if (isMine) {
this.books= // gets it from the database;
} else {
this. books= // gets it from the database
}
} else {
this. books = // gets it from the database
}
isMine - is a Boolean object
I tried with switch case by converting isMine to a string as below
String.valueOf(isMine)
But didn't work .Suggest a better and faster way to implement above code in java.
You can flatten your if-else statement by using else if:
if(isMine == null) {
books = allList;
} else if(isMine) {
books = myList;
} else {
books = notMyList;
}
Another approach would be to sperate the checks into methods:
public List<Book> getBookList(Boolean isMine) {
return isMine == null ? allList : getBookList(isMine.booleanValue());
}
public List<Book> getBookList(boolean isMine) {
return isMine ? myList : notMyList;
}
You can use Optional in this case:
Boolean isMine = null;
String str = "";
Optional<Boolean> optional = Optional.ofNullable(isMine);
str = optional.map(i -> i ? "a" : "b").orElse("c");
System.out.println(str);
So it will be something like:
this.books = optional.map(i -> i ? valForTrue : valForFalse).orElse(valForNull);
this.books = isMine != null ? (isMine ? this.myList : this.notMyList) : this.allList;
Using ternary operator inside of ternary operator e.g.
Do not even think about performance in your case, that's tiny.
Your current way looks good. And you have an answer with flatten way and nested ternary too.
If you still want to learn how to use switch in this case (please do not put this code in production. posting for showing you a way)
Correct way to achieve using String.valueOf(isMine) is
switch ( String.valueOf(isMine) ) {
case "null":
//TODO
break;
case "true":
//TODO
break;
case "false":
//TODO
break;
}
With pattern matching provided by vavr.io it can get very clean:
List<Books> output = Match(input).of(
Case($(true), dbCallX()),
Case($(false), dbCallY()),
Case($(), dbCallZ()));

how to write function for multiple if-else statements

I am new to Java. I have lots of multiple if-else statements. For code optimization purpose I need to write one function for all if else logic.
if (obj.getJSONObject("page_1").has("city")) {
sn.city = (String) obj.getJSONObject("page_1").get("city").toString();
} else {
sn.city = null;
}
// param 2 - locality
if (obj.getJSONObject("page_1").has("locality")) {
locality = (String) obj.getJSONObject("page_1").get("locality").toString();
} else {
locality = null;
}
I have like 110 if -else statements. I don't have any idea how to optimize the code.
I might write a function something like:
static String getToStringOrNull(JSONObject parent, String key) {
return parent.has(key) ? parent.get(key).toString() : null;
}
which you can then call like
sn.city = getToStringOrNull(obj.getJSONObject("page_1"), "city");
locality = getToStringOrNull(obj.getJSONObject("page_1"), "locality");
I think the best use would be this notation (ternary operator):
sn.city = (obj.getJSONObject("page_1").has("city")) ?
(String) obj.getJSONObject("page_1").get("city").toString() : null;
The part before ? stands for the if-statement, the second part if the condition was fulfilled and the last part otherwise.
For all direct fields of your class, you may use reflection (and you could do the same work on the sn object if you want ) :
Class aClass = this.getClass();
Field[] fields = aClass.getFields();
for (Field field : fields) {
String value = (obj.getJSONObject("page_1").has(field.getName())) ?
(String) obj.getJSONObject("page_1").get(field.getName()).toString() : null;
field.set(this, value);
}

How to avoid a lot of if else conditions

I have read a lot of topics about code refactoring and avoiding of if else statements. Actually, I have a class where I am using a lot of if - else conditions.
More details: I am using the pull parser and on each line of my soap response, I will check if there is a tag I am interested on, if not, check another tag etc:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
else if (soapResponse.equals("EditorialBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
}
else if (soapResponse.equals("AdvisoryBoard")){
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
}
eventType = xpp.next();
}
Now, I would like to use something else, instead of those if else conditions, but I don't know what.
Can you please give me an example?
Try to look at the strategy pattern.
Make an interface class for handling the responses (IMyResponse)
Use this IMyResponse to create AdvisoryBoardResponse, EditorialBoardResponse classes
Create an dictionary with the soapresponse value as key and your strategy as value
Then you can use the methods of the IMyResponse class by getting it from the dictionary
Little Example:
// Interface
public interface IResponseHandler {
public void handleResponse(XmlPullParser xxp);
}
// Concrete class for EditorialOffice response
private class EditorialOfficeHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Office response
}
}
// Concrete class for EditorialBoard response
private class EditorialBoardHandler implements IResponseHandler {
public void handleResponse(XmlPullParser xxp) {
// Do something to handle Editorial Board response
}
}
On a place you need to create the handlers:
Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>();
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler());
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler());
Where you received the response:
IResponseHandler responseHandler = strategyHandlers.get(soapResponse);
responseHandler.handleResponse(xxp);
In this particular case, since the code is essentially identical for all 3 case except for the String being appended to, I would have a map entry for each of the Strings being built:
Map<String,String> map = new HashMap<String,String>();
map.put("EditorialOffice","");
map.put("EditorialBoard","");
map.put("AdvisoryBoard","");
// could make constants for above Strings, or even an enum
and then change your code to the following
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
String current = map.get(soapResponse);
if (current != null && xpp.getText()!=null) {
map.put( soapResponse, current += xpp.getText());
}
eventType = xpp.next();
}
No "if... then... else". Not even the added complexity of multiple classes for strategy patterns, etc. Maps are your friend. Strategy is great in some situations, but this one is simple enough to be solved without.
In Java 7 you can SWITCH on Strings. You could use that if you could use that ;-)
Besides zzzzzzz(etc.)'s comment... keep in mind that you are using XmlPullParser which makes you write ugly code like the one you have. You could register some callbacks that would split your code and make it 'better', but if possible, just use SimpleXML library or similar.
Also, you can refactor your code to make it more readable and less verbose. For instance, why do you call xpp.next() inside each if statement? Why not just calling it outside just once:
if(eventType == XmlPullParser.START_TAG) {
soapResponse= xpp.getName().toString();
if (soapResponse.equals("EditorialOffice") && xpp.getText()!=null){
editorialOffice += xpp.getText();
}
else if (soapResponse.equals("EditorialBoard") && xpp.getText()!=null){
editorialBoard += xpp.getText();
}
else if (soapResponse.equals("AdvisoryBoard") && xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
}
eventType = xpp.next();
You could create a ResponseHandler interface with three implementations, one for each branch of your if/else construct.
Then have either a map mapping the different soapResponses to a handler, or a list with all the handler if it can handle that soapResponse.
You also should be able to move some of the boilerplate code to a common possibly abstract implementation of the response handler class.
As so often there a many variations of this. By utilizing the code duplication one actually needs only one implementation:
class ResponseHandler{
String stringToBuild = "" // or what ever you need
private final String matchString
ResponseHandler(String aMatchString){
matchString = aMatchString
}
void handle(XppsType xpp){
if (xpp.getName().toString().equals(matchString){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialOffice += xpp.getText();
}
}
}
}
Your code becomes
List<ResponseHandler> handlers = Arrays.asList(
new ResponseHandler("EditorialOffice"),
new ResponseHandler("EditorialBoard"),
new ResponseHandler("AdvisoryBoard"));
if(eventType == XmlPullParser.START_TAG) {
for(ResponseHandler h : handlers)
h.handle(xpp);
}
vast question that is this one and there is no real answer. (and I don't use soap very often)
here a just some ideas based on your code:
first you can groupe duplicate code
if (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard")){
Another good thing you can do is play around with switch staments like:
switch(soapResponse){
case "EditorialOffice":
case "EditorialBoard":
case "AdvisoryBoard":
eventType = xpp.next();
if (xpp.getText()!=null){
advisoryBoard += xpp.getText();
}
break;
Also you should consider breaking down you test into small functions:
public bool interestingTag(string s){
return (soapResponse.equals("EditorialOffice")
||soapResponse.equals("EditorialBoard")
||soapResponse.equals("AdvisoryBoard"));
}
public processData(xpp){
eventType = xpp.next();
if (xpp.getText()!=null){
editorialBoard += xpp.getText();
}
....}
So that you can just process all your answers in a while loop and you super long if else becomes a 5~10 line function
But as I said there are so many good ways of doing the same thing
You haven't mentioned if you can or do use Java 7. As of that java version you can use Strings in switch statements.
Other than that, encapsulating the logic for each case is a good idea, for example:
Map<String, Department> strategyMap = new HashMap<String, Department>();
strategyMap.put("EditorialOffice", new EditorialOfficeDepartment());
strategyMap.put("EditorialBoard", new EditorialBoardDepartment());
strategyMap.put("AdvisoryBoard", new AdvisoryBoardDepartment());
Then you can simply select the correct strategy from the Map and use it:
String soapResponse = xpp.getName();
Department department = strategyMap.get(soapResponse);
department.addText(xpp.getText());
Department is of course in interface...
You can define an enum like the following:
public enum SoapResponseType {
EditorialOffice(1, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
EditorialBoard(2, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
},
AdvisoryBoard(3, "description here") {
public void handle(XmlPullParser xpp) {
//do something you want here
return null;
}
};
public static SoapResponseType nameOf(String name) {
for (SoapResponseType type : values()) {
if (type.getName().equalsIgnoreCase(name)) {
return type;
}
}
return null;
}
public void handle(XmlPullParser xpp) {
return null;
}
}
Use above enum like this:
SoapResponseType type = SoapResponseType.nameOf("input string");
if (type != null) {
type.handle(xpp);
}
It's clean code, isn't it!

Elegant way to write criteria based if statements

I'm trying to find an object in a list based on a set of criteria. The basic logic looks like this
for (objectx obj : list)
{
if (object.property1 > criteria1)
//accept object
else (object.property1 == criteria1)
{
if (object.property2 > criteria2)
//accept object
else (object.property2 == criteria2)
{
if (object.property3 > criteria3)
... etc
}
}
}
Is there an elegent way to simplify this mess?
boolean accept = false;
for (int i = 0; i < object.numProps(); i++) {
if (object.prop[i] > criteria[i]) {
accept = true;
break;
} else if (object.prop[i] < criteria[i])
break;
// loop continues only if object.prop[i] == criteria[i]
}
I would create a method that checks all of the properties then inside your loop you can simply say:
for (objectx obj : list)
{
if(checkProperties(obj))
{
//Do Stuff
}
}
Adding methods named after your business logic may help. Then reading the code should read like english and the actual comparisons are somewhere else. It makes it easier to think about too.
If you want to do something like I did before that can help. I wanted to search for objects in database with NHibernate like you did. I created Query object to collect every criteria entered by user . And When I set the related property on Query object I added this criteria like this.
public bool Archive
{
set
{
if(value)
{
criteria.Add(Restrictions.Eq("Archive", true));
}
}
}
public bool IsFavorite
{
set
{
if (value)
{
criteria.Add(Restrictions.Eq("IsFavorite", true));
}
}
}
If you just want to filter objects in memory. You can also use Specification Pattern.

Categories

Resources