We're refactoring a long method; it contains a long for loop with many continue statements. I'd like to just use the Extract Method refactoring, but Eclipse's automated one doesn't know how to handle the conditional branching. I don't, either.
Our current strategy is to introduce a keepGoing flag (an instance variable since we're going to want to extract method), set it to false at the top of the loop, and replace every continue with setting the flag to true, then wrapping all the following stuff (at different nesting levels) inside an if (keepGoing) clause. Then perform the various extractions, then replace the keepGoing assignments with early returns from the extracted methods, then get rid of the flag.
Is there a better way?
Update: In response to comments - I can't share the code, but here's an anonymized excerpt:
private static void foo(C1 a, C2 b, C3 c, List<C2> list, boolean flag1) throws Exception {
for (int i = 0; i < 1; i++) {
C4 d = null;
Integer e = null;
boolean flag2 = false;
boolean flag3 = findFlag3(a, c);
blahblahblah();
if (e == null) {
if (flag1) {
if (test1(c)) {
if (test2(a, c)) {
Integer f = getF1(b, c);
if (f != null)
e = getE1(a, f);
if (e == null) {
if (d == null) {
list.add(b);
continue;
}
e = findE(d);
}
} else {
Integer f = getF2(b, c);
if (f != null)
e = getE2(a, f);
if (e == null) {
if (d == null) {
list.add(b);
continue;
}
e = findE(d);
}
flag2 = true;
}
} else {
if (test3(a, c)) {
Integer f = getF2(b, c);
if (f != null)
e = getE2(a, f);
if (e == null) {
if (d == null) {
list.add(b);
continue;
}
e = findE(d);
}
flag2 = true;
} else {
if (d == null) {
list.add(b);
continue;
}
e = findE(d);
flag2 = true;
}
}
}
if (!flag1) {
if (d == null) {
list.add(b);
continue;
}
e = findE(d);
}
}
if (e == null) {
list.add(b);
continue;
}
List<C2> list2 = blahblahblah(b, list, flag1);
if (list2.size() != 0 && flag1) {
blahblahblah();
if (!otherTest()) {
if (yetAnotherTest()) {
list.add(b);
continue;
}
blahblahblah();
}
}
}
}
This is one of those fun ones where no single pattern will get you there.
I would work at it iteratively.
First I'd try to see if I couldn't use an early continue to remove one of those levels of ifs. It's much clearer code to check for a condition and return early (or in your case continue) than to have deeply nested ifs.
Next I think I'd take some of the inner chunks and see if they couldn't be extracted into a separate method. It looks like the first two big blocks (within the "if (test2(a, c)) {" and its else statement) are very similar. There is cut and paste logic that should be the same.
Finally after that stuff is cleared up, you can start looking at your actual problem--you need more classes. This entire statement is probably a three line polymorphic method in 3-5 sibling classes.
It's very close to throw-away and rewrite code, once you identify your actual classes, this entire method will vanish and be replaced with something so simple it hurts. Just the fact that it's a static utility method should be telling you something--you don't want one of those in this type of code.
Edit (After looking a little more):
There is so much here it would be really fun to go through. Remember that when you are done you want no code duplication--and I'm pretty sure this entire thing could be written without a single if--I think all your ifs are cases that could/should easily be handled by polymorphism.
Oh, and as an answer to your question of eclipse not wanting to do it--don't even TRY automatic refactoring with this one, just do it by hand. The stuff inside that first if() needs to be pulled out into a method because it's virtually identical to the clause in its else()!
When I do something like this, I usually create a new method, move the code from the if into the new method (leaving just a call to the new method inside the if), then run a test and make sure you didn't break anything.
then go line by line and check to ensure there is no difference between the if and its else code. If there is, compensate for it by passing the difference as a new variable to the method. After you're sure everything is identical, replace the else clause with a call. Test again. Chances are at this point a few additional optimizations will become obvious, you'll most likely lose the entire if by combining it's logic with the variable you passed to differentiate the two calls.
Just keep doing stuff like that and iterating. The trick with refactoring is to use Very Small Steps and test between each step to ensure nothing changed.
continue is basically an analogue of an early return, right?
for (...) {
doSomething(...);
}
private void doSomething(...) {
...
if (...)
return; // was "continue;"
...
if (!doSomethingElse(...))
return;
...
}
private boolean doSomethingElse(...) {
...
if (...)
return false; // was a continue from a nested operation
...
return true;
}
Now I must admit that I didn't quite follow your current strategy, so I might have just repeated what you said. If so, then my answer is that I can't think of a better way.
If I were faced with your situation I would look at using other refactoring techniques such as "replace conditional with polymorphism". That said you should always do one thing at a time, so if you first want to extract method you have two options:
Add the "keepGoing" flag
Throw an exception from the method
Of these two options, I think the keepGoing flag is better. I wouldn't stop refactoring after you extract the method. I am sure once you have a smaller method you will find a way to remove this flag and have cleaner logic.
I'm going to summarize the answers here, while accepting Bill K's answer as the most complete. But everyone had something good to offer, and I might use any of these approaches next time I'm faced with this sort of situation.
mmyers: Cut out the loop body, paste it into a new method and replace all the continues with returns. This worked very nicely, although it would have trouble if there were other control flow statements, like break and return, inside the loop.
Bill K: Tease it apart iteratively; look for duplication and eliminate it. Take advantage of polymorphic classes to replace the conditional behavior. Use Very Small Steps. Yes; this is all good advice, with broader applicability than just this specific case.
Aaron: Either use the keepGoing flag to replace the continue or throw an Exception. I didn't try this, but I think the Exception option is a very nice alternative, and one I hadn't considered.
Related
boolean isRoleOld,isRoleNew;
for (Relations relation : listOfRelations)
{
if (Constants.ROLE_OLD.equalsIgnoreCase(relation.getRole()))
{
isRoleOld = true;
}
if (Constants.ROLE_NEW.equalsIgnoreCase(relation.getRole()))
{
isRoleNew = true;
}
}
if (isRoleOld && isRoleNew)
{
“Success”
}else{
throw Exception();
}
What i have done yet is
if (listOfRelations.stream()
.anyMatch(relation -> Constants.ROLE_OLD.equalsIgnoreCase(relation.getRole()))
&&
listOfRelations.stream()
.anyMatch(relation -> Constants.ROLE_NEW.equalsIgnoreCase(relation.getRole())))
{
System.out.println("Success");
}
How to use streams from Java8 to optimize this code. Using a anymatch twice is not the point.
Any help will be appreciated.
You could use a stream to map to each Role, and filter to identify old/new role match, then count the distinct matches.
long count = listOfRelations.stream().map(Relations::getRole)
.filter(role -> Constants.ROLE_OLD.equalsIgnoreCase(role)
|| Constants.ROLE_NEW.equalsIgnoreCase(role))
.map(String::toLowerCase)
.distinct().count();
if (count != 2) {
throw new Exception();
}
System.out.println("Success");
However although this does only one pass through the stream it does not exit early once matched both roles so won't be ideal for large data-sets.
Actually, the solution with two .anyMatch checks is better because of short-circuiting when the required value is matched and therefore these checks may usually complete "sooner" than a full single run over the entire stream. In case ROLE_OLD value is missing, && short-circuiting occurs and no check for ROLE_NEW is executed. The worst case is when ROLE_OLD is located at the end of the input listOfRelations, and no ROLE_NEW is there.
Similar loop-based solution would use break as soon as both ROLE_OLD and ROLE_NEW have been detected; in the worst case, the collection is fully iterated one time.
It seems widely accepted that assert statements should be reserved for testing and disabled in production because errors should have been resolved by then, and enabling assertions affects performance. However surely the same could be said of null checks with if statements. Why is this code considered good for production
if(x != null) {
x.setId(idx);
if (y != null) {
if (y.id == x.id) {
x.doSth();
}
} else {
//handle error
}
} else {
//handle error
}
but this code isn't? (Assuming assertions are enabled)
try {
assert(x != null);
x.setId(idx);
assert(y != null);
if (y.id == x.id) {
x.doSth();
}
} catch (AssertionError e) {
//handle error
}
I understand using an if statement when it's expected that a variable may not be initialized. However when it's for defensive coding, assert seems more elegant and readable.
I also tested performance for each method with this:
public class AssertTest {
static final int LOOPS = 10000000;
public static void main(String[] args) {
String testStr = "";
long startNotEqualsTest = System.currentTimeMillis();
for (int i = 0; i < LOOPS; i++) {
if (testStr != null) {
testStr = System.currentTimeMillis() + "";
} else {
throw new RuntimeException("We're doomed");
}
}
long notEqualsTestDuration = System.currentTimeMillis() - startNotEqualsTest;
testStr = "";
long startAssertTest = System.currentTimeMillis();
for (int i = 0; i < LOOPS; i++) {
try {
assert(testStr != null);
testStr = System.currentTimeMillis() + "";
} catch (AssertionError e) {
throw new RuntimeException("We're doomed");
}
}
long assertTestDuration = System.currentTimeMillis() - startAssertTest;
System.out.println("Duration with if : " + notEqualsTestDuration + "ms");
System.out.println("Duration with assert : " + assertTestDuration + "ms");
}
}
Timing is about the same for both methods:
Duration with if : 1234ms
Duration with assert : 1313ms
Disabling assertions makes very little difference:
Duration with if : 1391ms
Duration with assert : 1375ms
Have I missed any compelling reasons why null checks with if conditions are preferable to assert?
Ask yourself how you would handle the null cases? What do you do if an object is null that should not be. In most of the cases it absolutely ok to not handle it, at all. Just let it produce a NullPointerException sometime later in the execution. It is very likely to be a programming error, anyway, so it's ok to be caught by an ExceptionHandler eventually writing it to the logs.
Of course, there are cases when you need to react on null objects. if-else is made for such cases. It's easy, self-explaining, every programmer knows that construct, so why not using it. assert in production is discouraged, anyway. See this post on SO, for instance. And, for my taste, it's quite cumbersome with the try/catch block.
There are other options, as well. For instance, DavidW suggested to use annotations, which is perfectly fine, as long as you make sure that these annotations are interpreted (can be an issue when migrating code, for example).
Another approach are Validator classes. For instance, the Apache Commons library has a Validate class that checks for certain conditions and would throw an appropriate exception if the condition is not fullfilled. Of course, you can write your own Validators that will throw your custom exceptions, as well. You'll end up with a short concise one-liner like
Validate.notNull(myObj)
Validate.hasEmailCorrectSyntax("foo#bar.com");
Also take a look at Java's Object.requireNotNull
Using assert at all has to presume that the -ea flag is enabled, and in many instances...it isn't. The assert will accomplish the same thing as the null checks, with the clear side-effect that if one doesn't have their environment configured in a particular way, the code will not function as they expect.
For that reason, it makes sense to eschew assert and leverage the null checks where necessary. More concisely, if one can, it's preferable to wrap everything that could be null in an Optional instance and operate on it using ifPresent (or orElseThrow since you seem to want to indicate an error if those values are null) instead.
In my experience, if x or y being null is, in fact, an error then (instead of your first example) what will be coded is:
void someFunction(AnObject x, AnObject y) {
if (x == null || y == null) {
throw new IllegalStateException("Contract violation: x and y must be non-null");
}
// rest of method can be run without null checks.
}
As I've noted in some of the discussion below, if you know up front that certain parameter values are breaking (like null or NaN in a float/double) then it makes a lot of sense to fail fast. It helps callers isolate the problem better than if a null value gets put in a Map and the NPE gets thrown on another thread, for instance.
(Note: edited to remove a contentious suggestion to use annotations.)
given a java code such as:
Something v = a.getB().getC().getD().getE();
Is there a way in Eclipse (templates or external plugins) to generate a safe chain call as:
if(a!=null &&
a.getB()!=null &&
a.getB().getC()!=null &&
a.getB().getC().getD()!=null &&
a.getB().getC().getD().getE()!=null){
Something v = a.getB().getC().getD().getE();
}
Have you given any thought to a try{} catch(NullPointerException e){} block? It might feel less elegant, but it will stop your code if any of the method calls fails because the previous one returned null, and it will give you the chance to give the default value if it is null.
Another option would be something like this:
Something v = /*Default Value*/ // Will be overwritten if subsequent methods succeed.
Object temp = a.getB(); // Use whatever Object type getB() returns.
if(temp != null){
temp = temp.getC();
/* If getC() returns a different type of object,
* either use a different variable or make the temp variable even broader
* (such as the generic Object type) */
if(temp != null){
temp = temp.getD();
if(temp != null){
temp = temp.getE();
if(temp != null)
v = temp;
/* If all previous calls returned something substantial,
* v will be something useful */
}//if(getE() != null)
}//if(getD() != null)
}//if(getC() != null)
}//if(getB() != null)
If you want, you could use a slightly less CPU efficient, but easier to read, version by not nesting the if statements. If all of the if statements are executed after eachother, a single null will prevent all of the next statements from executing, although its value will still be checked every time.
As far as generating these statements, I'm not really sure. That will really depend on how far in advance you can predict what new methods will be available from the Object returned by previous method calls. If you're aiming for auto-generation of code, you might be better off with my first suggestion: try-catch
Do this only if no one will read your code. Try to avoid generated code especially the one you're asking for.
getB() method is called 4 extra times, etc.
By checking for null manually you'll learn coding faster and make less bugs not relying on automatic code correction ;)
In my java application I have a huge set of conditions which decides just one action. My question is how to make it look nice (I use NetBeans so I'd prefer solution that will not be broken by its code formatting function). I'd also like to have there as low amount of if/else statements as possible, because I think it will make it faster.
My original code was a mess, so I made an action diagram:. Take a copy if you want to play with it. Please keep in mind that the diagram is not perfect as to UML syntax, partly because I made it using google docs.
This is the code:
if (!config.get("checkForSpecials") || event.isNotSpecial()) {
if (config.get("filterMode").equals("blacklist")) {
if (!itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else if (config.get("filterMode").equals("whitelist")) {
if (itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else {
item.process();
}
}
There are two things I don't like about it - the conditions are not too clear (especially when I unfold full method names and config strings), and the fact that the process method call is there three times.
Factoring booleans out and caching return values from method calls can help clarify code.
In addition, plotting all the outcomes on a logic table can help. I use this tool to help.
With the linked tool:
A: config.get("filterMode").equals("blacklist")
B: config.get("filterMode").equals("whitelist")
C: filterContainsName (see below)
The tool churns out:
(!A && !B) || (!A && C) || (A && !C)
Which leads to the code below (with a small tweak that replaces (!A && C) with (B && C)):
boolean filterContainsName = itemFilter.contains(event.getItem().getName());
boolean useBlacklist = config.get("filterMode").equals("blacklist");
boolean useWhitelist = config.get("filterMode").equals("whitelist");
if (!config.get("safeMode") || event.isSafe()) {
if((!useBlackList && !useWhiteList) ||
( useWhiteList && filterContainsName) ||
( useBlackList && !filterContainsName)) {
item.process();
}
}
Use maps. The key of the map is the condition/case, the value is a single method class/anonymouse interface that contains the logic for that condition. Whenever you encounter a certain condition/case, you simply do a lookup in the map and execute the related function. This way you can even split up your logic-by-condition into seperate classes (if needed for sake of code beauty). As an added bonus you'll probably gain a performance bonus when the # of conditions > 10.
Looks good as it is to me. Perhaps you can isolate the valid conditions for calling item.process() to a method to make it more easier to understand.
if (!config.get("safeMode") || event.isSafe()) {
if (isItemValidForProcess(config, itemFilter, event)) {
item.process();
}
}
boolean isItemValidForProcess(config, itemFilter, event) {
String filterMode = config.get("filterMode");
if (filterMode.equals("whitelist")) {
return itemFilter.contains(event.getItem().getName());
}
if (filterMode.equals("blacklist")) {
return !itemFilter.contains(event.getItem().getName());
}
return true;
}
Believe it or not, the diagram is not that complex:)
There is no loop, and it is rather linear.
Here's a pseudo code that implements it
void action()
if <sort out specials>
if <is it special>
return;
if <check for unsafe items>
if not <safe items list contains item>
return;
if <filter status = on>
if < filter mode = whitelist>
if not <item is on filter>
return;
else // black list
if not <item is on filter>
return;
// finally!
[process item]
For really complex diagram, the answer is ... goto ...
I have some data that I'm querying in a single method.
It's gotten to the point where it's become the arrowhead anti-pattern.
It looks something like this:
void queryData()
{
int masterIndex = getMasterIndex();
if (masterIndex != -1)
{
byte[] pageData = getMasterPage(masterIndex);
if (pageData) != null)
{
Item1 i1 = getItem1(pageData);
Item2 i2 = getItem2(pageData);
if (i1 != null && i2 != null)
{
showResults(i1, i2);
}
}
}
}
Imagine the above but larger. More if statements and each method that is called has a decent amount of logic in it.
Now what I can do is refactor the above method so all if statements are positive and early return if true.
I feel it would be cleaner to break each query and validity check into their own class though.
Each action would inherit/implement an interface like the following:
public interface Action
{
public void run();
public boolean wasSuccessful();
}
I would create a list of the actions required and run through them one at a time.
This way it is obvious to see what logic belongs with each action.
Is this over architected? Is the above an existing pattern I don't know of yet?
Thanks in advance.
I would start off by abusing the "Extract Method" function of your IDE (if it has one) and pull out each logic branch into its own method. That way you make the code a lot more readable.
You'll probably want to start off writing a unit test first to make sure the result of your refactoring doesn't break or change the business logic of the code itself. Once you have refactored into smaller methods and are confident that the code still works as originally intended, you can then look at whether you can create classes and extract the code into those.
I wouldn't say that creating classes to have your queries and validity checks would be overengineered, as long as it makes sense and is readable. As you said, you could have a List<Action> and then loop through calling the run() method on each, then check wasSuccessful() on each and output the information as needed.
This way if you ever want to change the validation or query of a given action, you just change the class that the functionality is encapsulated in and you don't have to change your actual execution code.
Look how much cleaner it is with simply the early returns:
void queryData()
{
int masterIndex = getMasterIndex();
if (masterIndex == -1)
return;
byte[] pageData = getMasterPage(masterIndex);
if (pageData == null)
return;
Item1 i1 = getItem1(pageData);
Item2 i2 = getItem2(pageData);
if (i1 == null || i2 == null)
return;
showResults(i1, i2);
}
I think this is a better approach than creating an additional class structure.