Converting many 'if else' statements to a cleaner approach
You could have a Converter
interface. Then you could create a class for each Mimetype like:
public interface Converter {
public void convertToMp3();
public void convertToOgg();
}
public class MpegConverter implements Converter {
public void convertToMp3() {
//Code here
}
public void convertToOgg() {
//Code here
}
}
You would need a class like this for each converter. Then you could set up a map like this:
Map<String, Converter> mimeTypeMap = new HashMap<String, Converter>();
mimeTypeMap.put("audio/mpeg", new MpegConverter());
Then your convertToMp3
method becomes like this:
Converter converter = mimeTypeMap.get(mimeType);
converter.convertToMp3();
Using this approach you could easily add different converters in the future.
All untested, probably doesn't compile, but you get the idea
Modifying duplicate if-else statements into a cleaner code
With java-8 you could make it quite fancy by introducing a new method which accepts the numbers and an DoubleBinaryOperator
:
public void setAnswerText(double num1, double num2, DoubleBinaryOperator operator){
final double ans = operator.applyAsDouble(num1, num2);
final double doub = Math.round(ans * 100000.0) / 100000.0;
if(doub == (int) ans){
Answer.setText(Integer.toString((int) ans));
} else{
Answer.setText(Double.toString(doub));
}
}
and using a switch statement:
final double num1 = Double.parseDouble(FirstInput.getText());
final double num2 = Double.parseDouble(SecondInput.getText());
final String oper = (Operator.getText());
final DoubleBinaryOperator operator;
switch(oper){
case "+":
operator = (a, b) -> a+b;
break;
case "-":
operator = (a, b) -> a-b;
break;
case "/":
operator = (a, b) -> a/b;
break;
case "x":
operator = (a, b) -> a*b;
break;
default:
throw new UnsupportedOperationException();
}
setAnswerText(num1, num2, operator);
That way, you're finding the matching operator in the switch-statment and then executing the method with the numbers and the found operator
A cleaner if statement with multiple comparisons
Set<String> stuff = new HashSet<String>();
stuff.add("x");
stuff.add("y");
stuff.add("z");
if(stuff.contains(a)) {
//stuff
}
If this is a tight loop you can use a static Set.
static Set<String> stuff;
static {
stuff = new HashSet<String>();
stuff.add("x");
stuff.add("y");
stuff.add("z");
}
//Somewhere else in the cosmos
if(stuff.contains(a)) {
//stuff
}
And if you want to be extra sure nothing is getting modified while you're not looking.
Set<String> test = Collections.unmodifiableSet(new HashSet<String>() {
{
add("x");
add("y");
add("z");
}
});
If you just want to get some logic in there for a handful of hard coded conditions then one of the switch or if statement with newlines solutions might be better. But if you have a lot of conditions then it might be good to separate your configuration from logic.
Replacing if/else logic with state/strategy pattern
I think you should use GoF pattern Chain of responsibility. You should introduce two interfaces: 1) Condition
where you will check proper condition, e.g. "If the zip file does not exist" and return boolean result - "true" if condition is satisfied, otherwise "else", 2) Execution strategy
, that will run action assigned with condition, e.g. "download it from specified URL and then unzip it and read in file and move zip file to specified directory." So, 1st interface will be answer to the question "when", and 2nd - "then". "Condition" implementation and "execution strategy" implementation should be combined into "tuple" (or pair, entry, etc). This "tuple" should be moved to collection in order, that you've described. Then, when you need to handle zip file, you'll iterate over collection, invoking conditions and checking results, if result is "true" then invoking appropriate "execution strategy". Also, condition can be combined with execution strategy and moved into single interface/implementation with two methods. Context, that will describe current state of zip file can be passed between conditions/execution strategies.
Hope this helps.
Update.
Code example (in Java).
/**
* All implementations should check proper condition
*/
interface Condition {
/**
* Check if condition is satisfied
*
* @param pathToFile path to target file
* @return 'true' if condition is satisfied, otherwise 'false'
*/
boolean isSatisfied(String pathToFile); //i've made an assumption that you'll manipulate file path for checking file
}
...
/**
* Childs will wrap some portion of code (if you'll use language, that supports lambdas/functors, this interface/implementation can be replaced with lambda/functor)
*/
interface Action {
/**
* Execute some portion of code
*
* @param pathToFile path to target file
*/
void execute(String pathToFile);
}
...
class ZipFileExistsCondition implements Condition {
@Override
public boolean isSatisfied(String pathToFile) {
... //check if zip file exists
}
}
...
class ZipFileDoesNotExists implements Condition {
@Override
public boolean isSatisfied(String pathToFile) {
... //download zip file and move it to some temp directory
//if file downloaded ok, than return 'true' otherwise 'false'
}
}
...
class AlwaysSatisfiedCondition implements Condition {
@Override
public boolean isSatisfied(String pathToFile) {
... //always returns 'true', to run action assigned with this condition
}
}
...
Collection<Map.Entry<Condition, Action>> steps = Arrays.asList(
new AbstractMap.ImmutableEntry<Condition, Action>(new ZipFileExistsCondition(),
new Action() { /*move zip file to zip file directory and read in file*/ }),
new ZipFileDoesNotExists(), new Action() { /*download it from specified URL and then unzip it and read in file and move zip file to specified directory*/ },
new AlwaysSatisfiedCondition(), new Action() { /*create blank file and write it out to disk*/ }
);
...
String pathToFile = ...
...
for(Map.Entry<Condition, Action> step: steps) {
if(!step.getKey().isSatisfied(pathToFile))
continue;
step.getValue().execute(pathToFile);
}
Remarks:
1) you can implement 'Condition' as anonymous classes,
2) 'AlwaysSatisfiedCondition' can be singleton,
3) if you're using Java/Groovy/Scala, you can use Guava/Apache Commons 'Predicate' instead of 'Condition', 'Function' or 'Closure' instead of 'Action'.
If you need to exit after first 'satisfied' condition and appropriate action execution then just put 'break'/'return' after action execution.
How to refactor large if else block in java servlet front controller
Independently of the framework or technology, I've faced several times your case and what I always do is to use a command pattern:
https://en.wikipedia.org/wiki/Command_pattern
and in the command handler I use a Factory pattern that instantiates the appropriate class to handle the request with the information of the command object.
With this architecture you are veeery flexible and it is quite easy to implement :)
Replacing if else statement with pattern
This is a classic Replace Condition dispatcher with Command in the Refactoring to Patterns book.
Basically you make a Command
object for each of the blocks of code in your old if/else group and then make a Map of those commands where the keys are your condition Strings
interface Handler{
void handle( myObject o);
}
Map<String, Handler> commandMap = new HashMap<>();
//feel free to factor these out to their own class or
//if using Java 8 use the new Lambda syntax
commandMap.put("conditionOne", new Handler(){
void handle(MyObject o){
//get desired parameters from MyObject and do stuff
}
});
...
Then instead of your if/else code it is instead:
commandMap.get(someCondition).handle(this);
Now if you need to later add new commands, you just add to the hash.
If you want to handle a default case, you can use the Null Object
pattern to handle the case where a condition isn't in the Map.
Handler defaultHandler = ...
if(commandMap.containsKey(someCondition)){
commandMap.get(someCondition).handle(this);
}else{
defaultHandler.handle(this);
}
How to avoid many if-else statements
You could at least reduce the "verbosity" with Optional
.
String name;
if (stu.getName() != null) {
name = stu.getName();
} else {
name = "default"
}
Would become
String name = Optional.ofNullable(stu.getName()).orElse("default");
Th choice is yours to return an Optional
directly from the POJO Student
for any value that could be null
.
This would give a cleaner solution :
String name = stu.getName().orElse("default");
If getName
looks like :
public Optional<String> getName(){
return Optional.ofNullable(name);
}
Related Topics
Try with Resources VS Try-Catch
Where Do I Find a Standard Trie Based Map Implementation in Java
Spring Data JPA - How to Combine Multiple and and or Through Method Name
Spring Boot Adding Http Request Interceptors
Difference Between @JSONignore and @JSONbackreference, @JSONmanagedreference
Serving Static Files from Alternate Path in Embedded Jetty
Spring Boot Rest Service Exception Handling
Java 8's Streams: Why Parallel Stream Is Slower
What Is the Purpose of Flush() in Java Streams
Warning About Ssl Connection When Connecting to MySQL Database
Why Equals() Method When We Have == Operator
Using Bigdecimal to Work with Currencies
How to Connect to SQL Server Using Windows Authentication from Java Ee Webapp