How to write nested for loops in methodes (clean code) - java

Clean code means for me: only one task for each methode and no nested loops.
When I got the following code, I asked myself, how can I avoid nested for loops and encapsulate them in methods.
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
for (Option option : getOptions(context)) {
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
return group.getUser();
}
}
}
}
return "default";
}
My first solution was the following. The problem here is, the for loops are running until the end and do not break (return) when the value is found and set.
private String user = "default";
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
processOptions(context);
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
processGroups(option);
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
setUser(option, group);
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
}
}
so I wrote this code, which should be the same like the first:
private String user = "default";
private boolean isUserSet = false;
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if(!isUserSet) processOptions(context);
else return this.user;
}
return this.user;
}
private void processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if(!isUserSet) processGroups(option);
else return;
}
}
private void processGroups(Option option){
for (Group group : getGroups()) {
if(!isUserSet) setUser(option, group);
else return;
}
}
private void setUser(Option option, Group group){
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
isUserSet = true;
}
}
But then I asked myself, is this really better code? Is this more clean code? Yes, every method is only doing one thing. And yes, the code is better to read in my opinion. But from originally 12 lines compact code I now got 30 lines of code and one member variable more in the code. So is the first originally code better because it's more compact even with nested for loops?
What do you think? Which one is better? Or how can I write the code better?
Thanks in advance for your answers!

Instead of returning void, why not boolean?
private String getUser(){
for (FieldConfigScheme context : getConfigurationSchemes()) {
if (processOptions(context)) {
break;
}
}
return this.user;
}
private boolean processOptions(FieldConfigScheme context){
for (Option option : getOptions(context)) {
if (processGroups(option)) {
return true;
}
}
return false;
}
private boolean processGroups(Option option){
for (Group group : getGroups()) {
if (option.getValue().equalsIgnoreCase(group.getName())) {
this.user = group.getUser();
return true;
}
}
return false;
}
T.B.H. I prefer the nested loops method. It looks clean, there is nothing more going on in the loop than to simply find something in a hierarchy and this is perfectly fine.
The use of extra function in this case is just bad. Imagine having to debug this code now, rather than focusing on one method which is doing this, you will have to look at all the extra ones you made.
Also this method doesn't seem to take any parameters which suggests that it actually only needs to do this check once and the rest of the time it should just return the same value. That just a guess, but if that was the case, then it makes your efforts to make it cleaner all the more unnecessary.

Related

Modify java method body with spoon

I am trying to refactor old SimpleFormController. I would like to replace getSuccessView() and gerFormView() calls with actual success view and form view Strings.
I went through https://spoon.gforge.inria.fr/first_transformation.html, it shows how to generate and add statements however I could not understand how to modify.
I have tried couple of things.
Replace statements with the getSuccessView() and getFormView() calls
public class SimpleFormControllerReplaceViewCall extends AbstractProcessor<CtMethod> {
MetaData meta;
String successView= "successView";
String formView = "formView";
public SimpleFormControllerReplaceViewCall(MetaData meta) {
this.meta = meta;
}
#Override
public boolean isToBeProcessed(CtMethod candidate) {
if(candidate.getBody() == null) { //Ignore abstract methods
return false;
}
String sourceCode;
try {
sourceCode = candidate.getBody()
.getOriginalSourceFragment()
.getSourceCode();
} catch (Exception e) {
return false;
}
return sourceCode.contains(getViewFunctionName(successView))
|| sourceCode.contains(getViewFunctionName(formView));
}
#Override
public void process(CtMethod method) {
Node beanNode = getBeanNode(method);
CtBlock<Object> body = getFactory().createBlock();
method.getBody().getStatements()
.stream()
.map(s -> {
Optional<String> sourceCode = getStatementSourceCode(s);
if(!sourceCode.isPresent()) {
return s.clone(); // Clone required to handle runtime error for trying attach a node to two parents
} else {
System.out.println("Modifying: " + method.getSignature());
String code = sourceCode.get();
code = replaceViewCalls(beanNode, code, successView);
code = replaceViewCalls(beanNode, code, formView);
return getFactory().createCodeSnippetStatement(code);
}
}).forEach(body::addStatement);
method.setBody(body);
}
private Optional<String> getStatementSourceCode(CtStatement s) {
String sourceCode = null;
try {
sourceCode = s.getOriginalSourceFragment()
.getSourceCode();
} catch (Exception e) {}
System.out.println(sourceCode);
if (sourceCode != null &&
(sourceCode.contains(getViewFunctionName(successView))
|| sourceCode.contains(getViewFunctionName(formView)))) {
sourceCode = sourceCode.trim();
if(sourceCode.endsWith(";"))
sourceCode = sourceCode.substring(0, sourceCode.length()-1);
return Optional.of(sourceCode);
} else {
return Optional.empty();
}
}
public String replaceViewCalls(Node beanNode, String code, String viewType) {
String getViewFunctionName = getViewFunctionName(viewType);
if (!code.contains(getViewFunctionName)) {
return code;
}
String view = AppUtil.getSpringBeanPropertyValue(beanNode, viewType);
return code.replaceAll(getViewFunctionName + "\\(\\)", String.format("\"%s\"", view));
}
public Node getBeanNode(CtMethod method) {
String qualifiedName = method.getParent(CtClass.class).getQualifiedName();
return meta.getFullyQualifiedNameToNodeMap().get(qualifiedName);
}
private String getViewFunctionName(String viewType) {
return "get" + viewType.substring(0, 1).toUpperCase() + viewType.substring(1);
}
}
This however adds unwanted at end of blocks if() {... }; This creates syntax errors when if {} else {} blocks contain return statement(s). Auto import is turned on and imports are not added when there is more one class with same name (e.g., Map is present in classpath from few libraries) - this is consistent with the document. Can this be avoided when refactoring code? Original java file has correct imports.
Another approach I tried is to directly manipulate the body as a whole.
#Override
public void process(CtMethod method) {
String code = method.getBody()
.getOriginalSourceFragment()
.getSourceCode();
Node beanNode = getBeanNode(method);
code = replaceViewCalls(beanNode, code, successView);
code = replaceViewCalls(beanNode, code, formView);
CtCodeSnippetStatement codeStatement = getFactory().createCodeSnippetStatement(code);
method.setBody(codeStatement);
}
this still has same auto import issue as first one. Apart from that it adds redundant curly braces, for examples
void method() { x=y;}
will become
void method() { {x=y;} }
That that will be pretty printed ofcourse.
Also javadocs for getOriginalSourceFragment() also has below warning
Warning: this is a advanced method which cannot be considered as part
of the stable API
One more thing I thought of doing is creating pattern for each type of usage of getSuccessView() like
viewName = getSuccessView();
return getSuccessView();
return ModelAndView(getSuccessView(), map); etc, however for that I will have to write a whole bunch of processors / templates.
Since it is simple replacement, easiest is do something like below
//Walk over all files and execute
Files.lines(Paths.get("/path/to/java/file"))
.map(l -> l.replaceAll("getSuccessView\\(\\)", "actualViewNameWithEscapedQuotes"))
.map(l -> l.replaceAll("getFormView\\(\\)", "actualViewNameWithEscapedQuotes"))
.forEach(l -> {
//write to file
});
Since I can avoid text manipulation with the help of spoon for things like changing modifiers, annotations, method name, annotations etc, I am hoping there should be a better way to modify the method body.
You should treat the processor input as an abstract syntax tree instead of a string:
public class SimpleFormControllerReplaceViewCall extends AbstractProcessor<CtMethod<?>> {
#Override
public boolean isToBeProcessed(CtMethod candidate) {
if(candidate.isAbstract()) { //Ignore abstract methods
return false;
}
return !candidate.filterChildren((CtInvocation i)->
i.getExecutable().getSimpleName().equals("getSuccessView")
|| i.getExecutable().getSimpleName().equals("getFormView")).list().isEmpty();
}
#Override
public void process(CtMethod<?> ctMethod) {
Launcher launcher = new Launcher();
CodeFactory factory = launcher.createFactory().Code();
List<CtInvocation> invocations = ctMethod.filterChildren((CtInvocation i)->
i.getExecutable().getSimpleName().equals("getSuccessView")
|| i.getExecutable().getSimpleName().equals("getFormView")).list();
for(CtInvocation i : invocations) {
if(i.getExecutable().getSimpleName().equals("getSuccessView")) {
i.replace(factory.createLiteral("successView"));
} else {
i.replace(factory.createLiteral("formView"));
}
}
}
}
Here the CtMethod AST is traversed in search for CtInvocation elements with the specified properties. The found elements are then replaced with new string literal elements.

Need design suggestions for nested conditions

I need to write the logic with many conditions(up to 30 conditions) in one set of rule with many if else conditions and it could end in between or after all the conditions.
Here is the sample code I have tried with some possible scenario. This gives me result but doesn't look good and any minor miss in one condition would take forever to track.
What I have tried so far is, Take out common conditions and refactored to some methods. Tried creating interface with conditions and various set would implement it.
If you have any suggestion to design this, would help me. Not looking for detailed solution but even a hint would be great.
private Boolean RunCondition(Input input) {
Boolean ret=false;
//First if
if(input.a.equals("v1")){
//Somelogic1();
//Second if
if(input.b.equals("v2"))
//Third if
if(input.c >1)
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(input.d.equals("Z1"))
System.out.println("Passed 1");
// Fourth Else
else{
System.out.println("Failed at fourth");
}
//Third Else
else{
if(input.aa.equals("v2"))
System.out.println("Failed at third");
}
//Second Else
else{
if(input.bb.equals("v2"))
System.out.println("Failed at second");
}
}
//First Else
else{
if(input.cc.equals("v2"))
System.out.println("Failed aat first");
}
return ret;
}
public class Input {
String a;
String b;
int c;
String d;
String e;
String aa;
String bb;
String cc;
String dd;
String ee;
}
The flow is complicated because you have a normal flow, plus many possible exception flows when some of the values are exceptional (e.g. invalid).
This is a perfect candidate to be handled using a try/catch/finally block.
Your program can be rewritten into following:
private Boolean RunCondition(Input input) {
Boolean ret=false;
try {
//First if
if(!input.a.equals("v1")) {
throw new ValidationException("Failed aat first");
}
//Somelogic1();
//Second if
if(!input.b.equals("v2")) {
throw new ValidationException("Failed at second");
}
//Somelogic2()
//Third if
if(input.c<=1) {
throw new ValidationException("Failed at third");
}
//Fourth if
//Somelogic2();
//Go fetch key Z1 from database and see if d matches.
if(!input.d.equals("Z1")) {
throw new ValidationException("Failed at fourth");
}
System.out.println("Passed 1");
} catch (ValidationException e) {
System.out.println(e.getMessage());
}
return ret;
}
Where you can define your own ValidationException (like below), or you can reuse some of the existing standard exception such as RuntimeException
class ValidationException extends RuntimeException {
public ValidationException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
/**
*
*/
private static final long serialVersionUID = 1L;
}
You can read more about this in
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
Make a separate class for the condition:
package com.foo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class App
{
static class Condition<T> {
final int idx;
final T compareValue;
public Condition(final int idx, final T compareValue) {
this.idx = idx;
this.compareValue = compareValue;
}
boolean satisfies(final T other) {
return other.equals(compareValue);
}
int getIdx() {
return idx;
}
}
public static void main( String[] args )
{
final List<Condition<String>> conditions = new ArrayList<Condition<String>>();
conditions.add(new Condition<String>(1, "v1"));
conditions.add(new Condition<String>(2, "v2"));
final List<String> inputs = new ArrayList<String>(Arrays.asList("v1", "xyz"));
boolean ret = true;
for (int i = 0; i < inputs.size(); i++) {
if (!conditions.get(i).satisfies(inputs.get(i)))
{
System.out.println("failed at " + conditions.get(i).getIdx());
ret = false;
break;
}
}
System.out.println("ret=" + ret);
}
}
#leeyuiwah's answer has a clear structure of the conditional logic, but exceptions aren't the right tool for the job here.
You shouldn't use exceptions to cope with non-exceptional conditions. For one thing, exceptions are really expensive to construct, because you have to walk all the way up the call stack to construct the stack trace; but you don't need the stack trace at all.
Check out Effective Java 2nd Ed Item 57: "Use exceptions only for exceptional conditions" for a detailed discussion of why you shouldn't use exceptions like this.
A simpler option is to define a little helper method:
private static boolean printAndReturnFalse(String message) {
System.out.println(message);
return false;
}
Then:
if(!input.a.equals("v1")) {
return printAndReturnFalse("Failed aat first");
}
// etc.
which I think is a simpler; and it'll be a lot faster.
Think of each rule check as an object, or as a Strategy that returns whether or not the rule passes. Each check should implement the same IRuleCheck interface and return a RuleCheckResult, which indicates if the check passed or the reason for failure.
public interface IRuleCheck
{
public RuleCheckResult Check(Input input);
public String Name();
}
public class RuleCheckResult
{
private String _errorMessage;
public RuleCheckResult(){}//All Good
public RuleCheckResult(String errorMessage)
{
_errorMessage = errorMessage;
}
public string ErrorMessage()
{
return _errorMessage;
}
public Boolean Passed()
{
return _errorMessage == null || _errorMessage.isEmpty();
}
}
public class CheckOne implements IRuleCheck
{
public RuleCheckResult Check(Input input)
{
if (input.d.equals("Z1"))
{
return new RuleCheckResult();//passed
}
return new RuleCheckResult("d did not equal z1");
}
public String Name();
}
Then you can simply build a list of rules and loop through them,
and either jump out when one fails, or compile a list of failures.
for (IRuleCheck check : checkList)
{
System.out.println("checking: " + check.Name());
RuleCheckResult result = check.Check(input);
if(!result.Passed())
{
System.out.println("FAILED: " + check.Name()+ " - " + result.ErrorMessage());
//either jump out and return result or add it to failure list to return later.
}
}
And the advantage of using the interface is that the checks can be as complicated or simple as necessary, and you can create arbitrary lists for checking any combination of rules in any order.

Appropriate Java design pattern to avoid method duplication

I have this scenario. I started working with a system that 'process' documents. The problem is, it seems to be the typical scenario where it started small, and went getting bigger and bigger constructing it one chunk at a time and now it needs to be refactored.
Each document type has an identifier (docID), and all of them share the same underlying result structure.
There is a huge master class that does all the job BUT inside this class there are several methods (almost one for each site) with its own logic. They all do almost the same with slight changes (i.e. formatting a string before setting it to a field in the result structure or doing some calculation and then setting the field in the result structure).
For example:
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
private void processDocs(){
Result result = new Result();
result = processDocGeneric(result);
if(docID == 1){
result = processDoc1(result);
}
else if(docID == 2){
result = processDoc2(result);
}
...
}
Ok, so I'm planning to refactor this and I'm considering some design patterns I know but I don't want the feel that I'm killing a roach with a bazooka.
Command pattern is maybe the first that comes to my mind, also Strategy pattern. My major concern with those is that I will have to create a class for every document type that has its own implementation of the processDoc method (There are around 15 at the moment). I mean, if that's the way to go, that would be it but if there's a simpler way of doing it that I don't know, it would be better (since the change is in a single method).
The other thing that I could do is moving all those method to a 'methods' class, and also move the if-else block to a single method with a docID parameter (process(int docID) and then call it from the main class. But that's just splitting the huge class. It would be "cleaner" but not optimal.
What would be the best approach to clean and split this huge class and make it scalable (since there would be new document types to be added in the future)?.
You can use factory or abstract factory design patterns maybe, In this patterns you can get your needed objects without having to specify the exact class of the object that will be created.
I propose a solution based on the Visitable / Visitor Pattern. this solution requires very little change to the Result class, while opening the door to new visiting objects, making it an easily extensible framework. I'm making heavy use of Java8's default interface method.
The Visitor / Visitable Interfaces:
public interface DocVisitor<T extends VisitableDoc> {
default void visit(T document){
switch(document.getDocId()){
case 1:
processDoc1(document);
break;
case 2:
processDoc2(document);
break;
// ... other cases...
default:
processDocGeneric(document);
break;
}
}
void processDocGeneric(VisitableDoc document);
void processDoc1(VisitableDoc document);
void processDoc2(VisitableDoc document);
}
public interface VisitableDoc {
int getDocId();
default void visit(DocVisitor visitor){
visitor.visit(this);
}
}
Slight modification of the Result class:
public class Result implements VisitableDoc { // New interface declared
int getDocId(){
return docId; // This might already exist
}
// Rest is unchanged, the default implementation will suffice
}
A Visitor Implementation:
public class DocProcessor implements DocVisitor<Result> {
#Override
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
#Override
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
#Override
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
}
Usage:
public static final main(String[] args){
List<Result> results = // Obtain results somehow
DocProcessor processor = new DocProcessor();
for(Result result: results){
processor.visit(result);
}
}
[How to] split this huge class and make it scalable (since there would be new document types to be added in the future
What I've done is merely to split Document data on Result class / Document Processing on DocProcessor class. If you have other processing that differ from type to type, and which can be extracted to an external class (no need for private field handling, private methods calling etc.), this framework os completely applicable.
If not, you should REALLY consider refactoring it to use polymophism! Make each Document type its own object. Use a strong abstract class to link them all, and if you have many methods that are shared accross several but not all types, then make sub-types accordingly - or use default methods! Java8 FTW
For this situation is applicable builder pattern.
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("This is a ")
.append(profession)
.append(" named ")
.append(name);
if (hairColor != null || hairType != null) {
sb.append(" with ");
if (hairColor != null) {
sb.append(hairColor).append(' ');
}
if (hairType != null) {
sb.append(hairType).append(' ');
}
sb.append(hairType != HairType.BALD ? "hair" : "head");
}
if (armor != null) {
sb.append(" wearing ").append(armor);
}
if (weapon != null) {
sb.append(" and wielding a ").append(weapon);
}
sb.append('.');
return sb.toString();
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}

java getting concept of OOP right

hi guys I already searched a lot but weren't really satisfied with what I found. hope it's the right place to ask this question.
I'm doing Java now for a small amount of time (changed from C) and have problems of getting a grip of how to structure my code best for OOP.
let's give a simple example:
If I'm using some predefined strings (let's say e.g. filepaths or error messages) I'm currently creating an own class doing something like:
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
Would it be better to create a Map, add everything to it and get it by key?
Or am I doing it completely wrong?
Second example:
let's say I return an error string somewhere
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
And anywhere else in my program I'm checking for the return value:
if (!string.equals("I HAVE AN ERROR")) {
//do something
}
else {
// handle error
}
that's obviously a bad way having to change the code twice once the error message changes. and yeah, I could define the error string the same way I'm doing it in the first example but as I'm not satisfied with that one either I'm reaching a dead end.
would be glad to hear some of your suggestions how to properly do OOP !
First example :
private static final String libPath = "\\this\\is\\a\\path\\";
private static final String notFoundMessage = "This hasn't been found";
public static String getLibPath() {
return libPath;
}
public static final String getNotFoundMessage() {
return notFoundMessage;
}
...
In this case, no need to create a Map. That is the right way to do it. Just note that the libPath would be better defined like this :
private static final Path libPath = Paths.get("this", "is", "a", "path");
(The class Path exists since Java 7, current version is Java 8)
Second example:
public String getSomething() {
if (something != null) {
return something;
} else {
//handle error, return string below
}
return "I HAVE AN ERROR";
}
No : Never return error codes in Java. Prefer using an exception.
Example :
public class ElementNotFoundException extends Exception {
...
}
public String getSomething() {
if (something == null) {
throw new ElementNotFoundException();
} else {
return something;
}
}
Then, you handle the exception like this :
try {
myObject.getSomething();
} catch(ElementNotFoundException e) {
//handle error
}
For the first example, take a look at Internationalization: http://docs.oracle.com/javase/tutorial/i18n/
You can use statics or maps, but sooner or later you will need to show the messages in several languages.
For the second example, it's better to use Exceptions as they are intended to be used when an abnormal condition (like an error) happens.
Anyway, with Exceptions take care not to use it as flow control structures: Why not use exceptions as regular flow of control?
Here are some examples for handling constants throug out your code:
1. Class
public final class MyConstants {
public static final int ERROR_CODE = -1;
}
if (getSomething() == MyConstants.ERROR_CODE) {
// ...
}
2. Interface
public interface MyConstantsHolder {
int ERROR_CODE = -1;
}
public MyClass implements MyConstantsHolder {
public void myMethod() {
if (getSomething() == ERROR_CODE) {
// ...
}
}
}

How to call a method whose name is the value of a string variable in java?

This is the code of the method that I want to simplify. The method name I call of SerializedExpFamMixture class is exactly the value of "model", my question is how to assign the value of "model" directly as the name of the method instead of using "if" to determine which method I should call. Since by using "if", I need to list all the possible values of "model" and judge which method I should use.
Thank you very much for help. I am new to java.
public static SerializedExpFamMixture RateMtxModel(String model)
{
SerializedExpFamMixture result=new SerializedExpFamMixture();
if(model=="kimura1980()")
result=SerializedExpFamMixture.kimura1980();
if(model=="accordance()")
result=SerializedExpFamMixture.accordance();
if(model=="pair()")
result=SerializedExpFamMixture.pair();
return result;
}
One way you can approach this is to use Reflection:
Method method = myClass.getClass().getMethod("doSomething", null);
method.invoke(myClass, null);
Since you are new to Java, it's time for some general pointers:
In Java, we usually name our methods with camelCase, so the first letter is lower case.
Also, in Java we usually leave the opening curly-bracket on the same line as the code (no newline).
Always use final on your variables. At least your parameters. That way you won't overwrite it, and thus won't have to try to figure out which value it actually has at runtime.
Use curly-brackets! Please!
The result variable is not actually needed.
Use the equals-method to compare Strings.
If you only want one result, use else-if
Fixing these things, your method looks like this:
public static SerializedExpFamMixture rateMtxModel(String model) {
if (model.equals("kimura1980()")) {
return SerializedExpFamMixture.kimura1980();
} else if (model.equals("accordance()")) {
return SerializedExpFamMixture.accordance();
} else if(model.equals("pair()")) {
return SerializedExpFamMixture.pair();
}
return new SerializedExpFamMixture();
}
Next, let's look at what you are actually trying to do here. You want to pass some Strings around, and use them as a basis for creating objects. And now, with the advice given here, you will do this using reflection. This does not sound like a very good idea to me. Say you were to go through with this, and this happened:
rateMtxModel("kinura1980");
Small typo, hard to spot, will give unexpected results. If you were actually calling a method the compiler would let you know that you messed up, now you will get no warning (btw did you see both errors in that method call?). The same if someone were to delete the accordance()-method, the compiler would not alert them that this will break the program.
If it was up to be I would just use the static factory-methods in SerializedExpFamMixture directly, but if you have to do it like this (if the task at hand is using a String input to create an object) I would do something like this:
public enum Something {
KIMURA1980("kimura1980()"),
ACCORDANCE("accordance()"),
PAIR("pair()");
private final String stringValue;
private Something(final String stringValue) {
this.stringValue = stringValue;
}
public static Something fromString(final String string) {
for (final Something something : values()) {
if (something.stringValue.equals(string)) {
return something;
}
}
return null;
}
}
public static SerializedExpFamMixture rateMtxModel(final String model) {
if (model == null) {
throw new IllegalArgumentException("model is null!");
}
final Something something = Something.fromString(model);
if (something == null) {
return new SerializedExpFamMixture();
}
switch(something) {
case KIMURA1980:
return SerializedExpFamMixture.kimura1980();
case ACCORDANCE:
return SerializedExpFamMixture.accordance();
case PAIR:
return SerializedExpFamMixture.pair();
default:
return new SerializedExpFamMixture();
}
}
This way, the one place where you will use the Strings is in the enum, the rest of the code will use the enum constants and thus have the safety of the compiler to rely on.
One could also leave the linking between operation and String to the enum, like this:
interface Operation<T> {
public T run();
}
public enum Something {
KIMURA1980("kimura1980()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.kimura1980();
}
}) ,
ACCORDANCE("accordance()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.accordance();
}
}),
PAIR("pair()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.pair();
}
}),
DEFAULT(null, new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return new SerializedExpFamMixture();
}
});
private final String stringValue;
private final Operation<SerializedExpFamMixture> operation;
private Something(final String stringValue, final Operation<SerializedExpFamMixture> operation) {
this.stringValue = stringValue;
this.operation = operation;
}
public static Something fromString(final String string) {
if (string != null) {
for (final Something something : values()) {
if (string.equals(something.stringValue)) {
return something;
}
}
}
return DEFAULT;
}
public SerializedExpFamMixture getCorrespondingSerializedExpFamMixture() {
return operation.run();
}
}
With this setup in the enum (I think the Operation-part can be trimmed out with Java8), the method will be as simple as:
public static SerializedExpFamMixture rateMtxModel(String model) {
return Something.fromString(model).getCorrespondingSerializedExpFamMixture();
}
Use reflection, but you need to consider a few things:
Bug alert! Comparing Strings using == doesn't work as expected in java - use .equals() instead. However, the solution below bypasses that problem
For the general case, which includes methods not visible to the invoker, you need to consider accessibility, both in finding the method and invoking it
You don't need the result variable, and even if using your code, don't need to initialize it
Try this:
String methodName = model.replace("(", "").replace(")", "");
try {
// getMethod() returns only public methods, getDeclaredMethod() returns any visibility
Method method = SerializedExpFamMixture.class.getDeclaredMethod(methodName);
// if the method is not guaranteed to be visible (eg public) you need this:
method.setAccessible(true);
return (SerializedExpFamMixture) method.invoke(null); // how to invoke on the class object
} catch (Exception forBrevity) {
return new SerializedExpFamMixture();
}

Categories