Refactoring If Statements For Better Readability - java

I'm currently working on a project that will diminish a class that being used by other several classes.
if(condition_A)
{
doSomething();
}
else if(condition_B)
{
classToBeRemoved();
}
else
{
doAnother();
}
The first solution that came up to me is to negate the condition of the if-else statement that will be modified.
if(condition_A)
{
doSomething();
}
else if(!condition_B)
{
doAnother();
}
This method of refactoring do not affect the functionality of the code but sometimes if the condition is too long, it affects the readability of the code.
Is there another way that will maintain the readability of the code other than negating the condition?

Maybe with functions, vaguely like:
List<BooleanSupplier> actions = new ArrayList<>();
actions.add(() -> {
if (!condition_A) {
return false;
}
doSomething();
return true;
});
actions.add(this::canDoSomething);
if (!actions.stream().anyMatch(p::get)) {
doAnother();
}
I took the liberty to abstract condition+action into a predicate, instead of using a Pair or such.
This is uglier, but could decouple things, as now the add's can come from outside the class, defining a public void addAction(BooleanSupplier action).
Though probably a parameter is needed to provide a data context (Predicate<?>).

Related

Java avoid using too many if statement or too many validator classes

I am using lot of if statements to check.Like:
if(statement 1){
block 1;
}
if(statement 2){
block 2;
}
...//about at least 20 if
if(statement n){
block n;
}
To avoid using too many if-statement, I have tried to use strategy pattern which would create validator class for each if-statement.Like:
public interface Validator<SomeObejct>{
public Result validate(SomeObject o);
}
public class SomeValidator implements Validator<SomeObject> {
#Override
public boolean validate(SomeObject o) throw Exception{
if(statement 1){
block 1;
}
}
Because I may have at least 20 if-statement, it may need at least 20 validator classes. So if there is any better solution for that? Or how can I manage these 20 validotor classes?
Edit:
To be more specific, I am writing some code for checking the problem on my schedule. For example:
if(currentDate > mustFinishDate){
warning();
}
if(NotScheduleADateForThisTask){
warning();
}
if(DateFormatNotCorrect){
error();
}
Above the date check may also be the if-statement block.
You can use the Composite pattern to maintain a list of all validators:
class ValidatorComposite<T> implements Validator<T> {
List<Validator<T>> validators = new ArrayList<>();
public void addValidator(Validator<T> add) { validators.add(add)); }
public Result validate(T toValidate) {
Result result = Result.OK;
for (Validator<T> v : validators) {
result = v.validate(toValidate);
if (result != Result.OK) break;
}
return result;
}
}
and since Validator only has one method, for Java 8 it's a functional interface, so you don't really need "20 classes" but can create a list on the fly using lambdas.
ValidatorComposite<SomeObject> val = new ValidatorComposite<>();
val.addValidator(so -> condition1 ? block1(so) : Result.OK);
val.addValidator(so -> condition2 ? block2(so) : Result.OK);
and so on.
Your code sample isn't really consistent because first you declare Validator to return Result and later let the implementation return boolean (and even throws an Exception), so I kind of intergrated both by ignoring the exception and using a Result.OK value.
these days what you should not probably care about is performance because of power of computers. now most programmers try to write readable and clean codes.
so i believe if writing 20 ifs makes your code easier to understand and more flexible its not bad to implement that.
BTW you can use switch case too.
switch (variable){
case 1:{
//block 1
}
case 2:{
//block2
}
...
}
if your cases are not similar and have different aspects using that Validator pattern will lead to inflexibility(It may lead to this point, it depends on situation).

Return in else branch of void function

Is it good or bad practice to have an else branch which only returns in a function that returns type void? Such as this code:
public void myFunc() {
if (<some condition>) {
//run some code
} else {
return;
}
}
Note that this topic is opinion based, you will probably see many different preferences from user to user.
For readability and maintainability you should try to reduce the complexity of your code. Therefore you want to also reduce the nesting. Thus my prefered variant would be:
public void myFunc() {
// Directly leave if condition does not hold
if (!condition) {
return;
}
// Now do the rest of the code
}
If you want to stick to your current variant then I would suggest to just drop the else part because it just aggravates the readability in my opinion, so:
public void myFunc() {
if (condition) {
// Do something
}
// You can always leave a comment if you think
// that helps a reader, so you can put "Do nothing
// if condition does not hold" here
}
However as said, I personally prefer the first variant because it reduces the nesting of the overall code.
No, this else statement is not required if you are not doing any operation.
The else statement is basically used to carry out an operation, if the condition of if do not met.The best practice is not to write the else statement, if you are not doing any operation.
public void myFunc() {
if (<some condition>) {
//call FunctionA();
} else {
//call FunctionB();
}
}
In the above case, the use of else is valid. But if you are not doing any operation, then the statement is useless. Please read Clean Code Book by Robert Cecil Martin. It will help you in writing clean code.
From the java.lang.Void class documentation:
The Void class is an uninstantiable placeholder class to hold a reference to the Class object representing the Java keyword void.
So any of the following would suffice:
Parameterizing with Object and returning new Object() or null.
Parameterizing with Void and returning null.
Parameterizing with a NullObject of yours.
You can't make this method void, and anything else returns something. Since that something is ignored, you can return anything.

How to refactor a big function with many if constructs?

We have App A as main app. Now we build from it App B which uses a subset of App A's functionality.
App A stays like it is whereas app B only uses a subset of A
So I want to refactor the function without or with as little dublication as possible and with maximum readability.
So the function looks like this (it is actually longer, this is an excerpt):
class SomeClass {
Data prepareData() {
if (this.bothId==1 || this.appAid=2 /*or only relevant for appA*/) {
if(this.data==null) { /*appA*/
appAdoSmth(); /*appA*/
}
boolean merge=false; /*appA*/
if (this.data==null) { /*appA*/
merge=appAanalyze(data); /*appA*/
}
bothPrepare(merge);
} else if (bothIsRelevant()) {
if(appArelevant()) { /*appA*/
data=appAprepare(); /*appA*/
} else {
data=prepareBoth();
}
bothUpdateSomeValue();
}
}
How would you do it?
Other Answers address the general question of how to refactor code. They offer good advice, but I don't think it is what you are asking.
I think you are asking about possible refactorings of the code in your question.
It is hard to give an answer that is generally applicable, or even specifically applicable. (The sample code isn't your real code, and it is a little difficult to understand what it actually "means").
AndreasD gives one approach: break the big complicated nested if into separate methods.
Another approach is to use the Stragegy design pattern. Separate the code that is specific to each app into strategy classes. For example:
interface Strategy {
Data prepareData();
}
class GeneralStrategy implements Strategy {
Data prepareData() {
// do general preparation
}
}
class App1Strategy extends GeneralStrategy {
Data prepareData() {
// do app1-specific preparation
super.prepareData();
// do more app1-specific preparation
}
}
and so on.
I ideal world develop unit test that validates that existing implementation of your function works.
Then start changing code incrementally and run your test after every change.
It is hard to give your formal recommendation without knowing your code structure. But generally try to find duplicate code fragments, write methods that implement this logic with parameters and replace the duplicate fragments to your new method. Etc, etc.
Good luck.
Readbility can be improved by extracting some logic in separate methods. That is a refactoring method.
Data prepareData() {
if (this.bothId==1 || this.appAid=2 ) {
handleCase1(); // <- you'll find better names for the methods
} else if (bothIsRelevant()) {
handleCase2();
}
}
private void handleCase1() {
if(this.data==null) {
appAdoSmth();
}
boolean merge=false;
if (this.data==null) {
merge=appAanalyze(data);
}
bothPrepare(merge);
}
private handleCase2() {
if(appArelevant()) {
data=appAprepare();
} else {
data=prepareBoth();
}
bothUpdateSomeValue();
}
This doesn't reduce the number of if/else, of course, but it keeps the "main" method simple.
If I were you I would run a coverage report on this class. (e.g. http://ecobertura.johoop.de/ or http://www.eclemma.org/) This way Eclipse can show covered lines green and this helps you to identify the cases. With this aid it's much easier to separate green lines and pull them into methods.

Java code PMD Complains about Cyclomatic Complexity , of 20

When i ran PMD on my Java Code , one of the Error Message it is showing is
"The class STWeb has a Cyclomatic Complexity , of 20 " .
Typically my java class is of this way
public class STWeb implements STWebService {
public String getData(RequestData request)
{
validate(request);
}
public boolean validate(Data[] formdata)
{
if(formdata.length==1)
//do this
else if(formdata.length==3)
//do this
else if(formdata.length==4)
//do this
else if(formdata.length>4)
//do this
else if(formdata.length==2)
{
if(formdata[0].getName.equals("OIY"))
{
}
/ And many more if else here
}
}
}
As you can see , as per my business requirements , i need to code the class
with many if's and if else so the reason the cyclocomplexity has ncreased , please tell me
what is feasible approach as per the standard for this ??
Cyclomatic Complexity measurements shouldn't be used for quality control, but rather as an indicator/warning for bad code. You should focus more on the code behind it rather than the value of the CC itself.
Although you can reduce the complexity of the validate method by splitting it into smaller methods through refactoring, the class as a whole will still have the same CC.
As long as the code is readable and makes sense to the next person that has to look at it, then having a higher CC shouldn't matter so much.
It helps if you have something like this:
if (a) {
return true;
} else if (b) {
return true;
} else if (c) {
return true;
} else {
return false;
}
then, you replace it with this:
return a || b || c;
Just wanted to add, that sometimes it's possible to resolve such problems with object- or structure-building. You could declare a "Wrapper-Class" for your data that is supposed to be returned. But there are always cases when you can't apply this without bloating the code with tons of objects, which in return also results in unreadable code ^^"
EDIT: this SO-post is a [nice example with ENUMS]
Cyclomatic complexity seems to indicate the amount of code paths that exist. So if your requirements say you must use many ifs and if elses, then you can ignore that message.
If this is mandatory - yes this happens despite it's futil - you can often reduce the class cyclomatic complexity by introducing base classes and move distribute the functions into the base classes until the per class cyclomatic complexity is ok.
Or simpler: add // NOPMD to your class:
public class VeryComplexStuff { // NOPMD
...

Using Return Stylishly

Let's say I had a lot of code between an if statement. Is it more proper to do a quick if-else check before it, and if it fails, return.
OR create the if statement with a lot of code in-between but not use return?
OR is it just a matter of preference?
so my 2 options are:
if(!something){
return
}
else
//lots of code here
if(something){
//lots of code here
}
From a performance perspective, you should always return from a function as quickly as you can, avoid doing unnecessary computations, "short-circuit" if you will. So checking for error cases and returning quickly would be the better policy.
Edit to add: In the same vein, you should always check the cases that are most likely to be violated first, this is sound advice when structuring your conditionals as well (|| and && checks)
I think this looks much nicer:
func() {
if(someCondition) {
return;
}
if(otherCondition) {
return;
}
//lots of code
}
than this:
func() {
if(someCondition) {
return;
} else if(otherCondition) {
return;
} else {
//lots of code
}
}
or this:
func() {
if(!someCondition) {
if(!otherCondition) {
//lots of code
}
}
}
It looks even uglier with more conditions, so I generally use the first method.
I prefer "shortcut". It has nothing to do with performance, as modern computer can handle if-else very fast, so we should focus on code readability.
However, if there's so many if-else in code, you may re-think your design. Refactory can be a better choice.
Readability and performance are not necessary conflicting constraints but when they are I tend to give readability the front seat.
To enhance readability I tend to follow the following rules.
Rule 1. Keep return as the last line of code, whatever comes in the middle. In other words don't sprinkle return statements whenever you want just because you're not too sure your if-else structure will cascade down just before the final return.
Except may be for the simplest methods I privilege a structure like
MyType func() {
MyType result ;
if ( condition ) {
result = result_1 ;
} else {
result = result_2 ;
}
return result ;
}
over an allegedly simpler
MyType func() {
if ( condition ) {
return result_1 ;
} else {
return result_2 ;
}
}
In my opinion the performance cost, if any, is negligible. However, when scaled up, I find the first coding pattern much more readable.
Rule 2. Refrain from starting a logic by "evacuating" error conditions, just in order to get them out of the way and free your mind. If your logic is well thought these checks will find their place in the logic (also have a look at guava for many well though techniques of encapsulating routine checks in helpers).
Many freshmen in my team start coding things like this
MyType func (ArgType arg1,...) {
if ( arg1 == null ) {
throw new Exception ( "hey dummy, we don't take null arg1) ;
// or return null ;
}
if ( arg2 == null ) {
// you got the picture...
}
// wow at last !!! all checks done
// Combine args and return result...
}
Which I have to say, is already a progress on just taking all conditions for granted
I tend to prefer
MyType func (ArgType arg1,...) {
MyType result ;
if ( try_to_compact_all_checks_here ) {
// Combine args and return result...
} else {
// throw, log, nullify result etc
}
return result ;
}
If the condition "try_to_compact_all_checks_here" does not fit in one line, I even sometimes prefer to get out of my way and I encapsulate all the checks in a private function. Even if it's called only once.
Rule 3. Keep the number of lines in an if/else statement to a reasonable amount (basically should fit on one screen in your IDE). To do so it is sometimes possible to extract some logic and stick it into a private function. No problem at all. All modern IDE do that for you in 2 clicks.
So basically the previous template becomes.
MyType func (ArgType arg1,...) {
MyType result ;
if ( checks_here ) {
// 1 to 20 lines max,
encapsulate lengthy logic in full fledged private methods.
} else {
// throw, log, nullify result etc
}
return result ;
}
Rule 4. Inner IFs should always have an ELSE, and that ELSE should be different from the outer ELSE.
Explanation: If I end up with
MyType func (ArgType arg1,...) {
MyType result ;
if ( check_1 ) {
if (check_2) {
Do the real work
} else {
treat error condition
}
} else {
same error condition as above
}
return result ;
}
Then it's probably because my check analysis is not complete. It happens quite often.
I try to reach
MyType func (ArgType arg1,...) {
MyType result ;
if ( check_1 && check_2) {
Do the real work
} else {
same error condition as above
}
return result ;
}
That's all.
I found that, by observing this kind of conventions, I can process large Java projects with ofter complex business logics (like in ESBs, Web Services etc), at very little performance cost if any.

Categories