How to avoid instanceof calls? - java

I defined this simple method:
public static boolean isBorder(int x, int y) throws CollisionDetectionException {
try {
if ( (levelItems[x][y] instanceof StaticGameObject && levelItems[x][y].isVisible()) ||
(levelItems[x-1][y] instanceof StaticGameObject && levelItems[x-1][y].isVisible()) ||
(levelItems[x][y+1] instanceof StaticGameObject && levelItems[x][y+1].isVisible()) ||
(levelItems[x][y-1] instanceof StaticGameObject && levelItems[x][y-1].isVisible()) ||
(levelItems[x-1][y-1] instanceof StaticGameObject && levelItems[x-1][y-1].isVisible()) ||
(levelItems[x-1][y+1] instanceof StaticGameObject &&levelItems[x-1][y+1].isVisible()) ||
(levelItems[x+1][y] instanceof StaticGameObject && levelItems[x+1][y].isVisible()) ||
(levelItems[x+1][y+1] instanceof StaticGameObject && levelItems[x+1][y+1].isVisible()) ||
(levelItems[x+1][y-1] instanceof StaticGameObject && levelItems[x+1][y-1].isVisible()) ) {
return true;
} else {
return false;
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new CollisionDetectionException("Collision couldn't be checked because checking position " + x + "/" + y + " caluclated values below (0/0)");
}
}
As you can see i have a 2dimensional array. Now i want to check a specific position ((x/y) -> the method arguments), if there are any visible StaticGameObject in the neighbouring fields of the 2dimensional array.
The levelItems array consists of so called GameObject. StaticGameObject is a a direct subclass of GameObject.
Any hints how to improve this method?

Add a method to GameObject
bool isBorderObject() { return false; }
Then override in StaticGameObject
bool isBorderObject() { return true; }
change the test to
(levelItems[x][y].isBorderObject() && levelItems[x][y].isVisible())
Also, the if could be this nested for
for (int i = x-1; i <= x+1; ++i) {
for (int j = y-1; j <= y+1; ++j) {
GameObject item = levelItems[i][j];
if (item.isBorderObject() && item.isVisible())
return true;
}
}
return false;

(Disclaimer: I've worked on Java games running on a lot of mobile devices)
People already showed how to simplify all these if statements. I'd add that defining your own CollisionDetectionException is probably completely overkill.
For a start, such low-level Java details don't exist at the OO level: exceptions, especially checked exceptions, are a Java idiosynchrasies that is really not necessary. Some very good and very impressive Java frameworks do mostly away with them, like Spring. Then a lot of very impressive and powerful apps, made of millions and millions of lines of code, run perfectly fine without ever using the concept of checked exception because they're, well, written in language in that don't have this kind of concept (once again: a "checked exception" doesn't exist at the OO level, hence any OOA/OOD to OOP without ever needing to use checked exception).
In any case: there's really no reason to turn an ArrayIndexOutOfBoundException into your own specific checked exception. This means you plan to use exception for flow control, which is a HUGE no-no.
Then, regarding your "isBorder" test... You probably don't need that. You think you do, but you really don't. Why do you want to know if it's a "border"? To detect a collision I guess.
You're using a static method to detect if it's a border, and static is the anti-thesis of OO. What is important is the messages you are passing around between objects. You may have all your objects responding to some isCollidingWith(...) message: objects that are "border" knows they are border, they'll know how to deal with a isCollidingWith(...) message.
Then you can go even further: instead of doing a isCollidingWith(...) you could have some resolveCollisionWith(...) method.
public class Wall implements MySuperAbstraction {
int wallHitPoints = 42;
boolean isWallStillUp = true;
void resolveCollisionWith( SomeObject o ) {
if ( o.isStrongEnoughToHarmWall ) {
wallHitPoints--;
isWallStillUp = wallHitPoints > 0;
}
}
}
This is just a quick piece of code and it doesn't deal with the fact that SomeObject needs probably to bounce when he hits the wall, etc. but the point stands: in OO objects knows how to communicate between themselves. They know how to deal with the various messages passed around.
If you want to do OO, then all I can tell you is that Java's static, instanceof and checked exceptions are definitely not the way the go. Basically, they're the anti-thesis of OO :)
]

This should get rid of the extremely large if block you have:
for(int col = x-1; col <= x+1; col++)
{
for(int row = y-1; row <= y+1; row++)
{
if(levelItems[row][col] instanceof StaticGameObject && levelItems[row][col].isVisible())
return true;
}
}
(This solution merely reduces the crazy if, not get rid of the instanceof, as you can see)
Of course, in both my example and yours, you should make sure to check for array bounds problems.

A revision to #Lou's solution which is to have one method and one loop.
for (int i = 0; i < 9; i++)
if (levelItems[x-1 + i/3][y-1 + i%3].isBorderObjectVisible())
return true;
return false;

Think about "inversion of control".
As an example, how could introducing this method to the GameObject class:
public boolean
isBorder()
{
return false;
}
and this override in the StaticGameObject class:
public boolean
isBorder()
{
return self.isVisible();
}
simplify the code above?

Another nice technique is to have a function that returns the set of adjacent cells. In this way you avoid (or anyway move) the double-loop. It's better separation of concerns; when you discover that your algorithm was forgetting about out-of-bounds conditions, there's exactly one place to fix it.
public Set<GameObject> adjacentItems(int x, int y) {
Set<GameObject> set = new HashSet<GameObject>();
for (int i = -1; i < 2; ++i)
for (int j = -1; j < 2; ++j)
set.add(levelItems[x+i][y+j]);
return set;
}
public boolean isBorder(int x, int y) {
for (GameObject item : adjacentItems(x, y))
if (item.isBorder() && item.isVisible())
return true;
return false;
}

Don't make this any more complex. Simply be sure all subclasses of GameObject implement isVisible. That's all it takes.
If you need to also distinguish moveable vs. non-movable, then you need two methods:
isVisible -- visible or not
isMovable -- moveable or not
You never need instanceof.
[It's not clear from the question, but it appears that the class StaticGameObject actually means is a subclass of GameObject with isMovable() false.]

Related

Refactor function overloaded methods in just one method

Currently I have a method overloading the following method:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
}
public boolean isHorizontalOrVertical(List<Point> points) {
if (points == null || points.size() < 2) {
throw new IllegalArgumentException("invalid number of points");
}
Point start = points.get(0);
return points.stream()
.allMatch(p -> isHorizontalOrVertical(start, p));
}
The method is needed to check if two or three points are vertical/horizontal to each other. In the case of three points, it just has to check if the two last points are horizontal/vertical to the start point.
Does anyone have any idea how I can get it all into just one method?
First and foremost I have to note the fact that it doesn't make sense, to me at least, a method which calculates if two entities are horizontal or vertical and those entities are Points. How can two points be horizontal or vertical?
isHorizontalOrVertical is a bad name
Overcoming the above, you could create a single method which calculates if two points are horizontal or vertical.
Change the name isHorizontalOrVertical because it's redundant. A better name is isHorizontal or isVertical. The method will return a boolean so if isHorizontal returns false, then it's vertical and vice versa. Probably a better name could be areTwoPointsHorizontal but I am having trouble even writing that because it transmits the wrong message, but feel free to choose your own.
So the method,
public boolean isHorizontal(Point first, Point second){
boolean sameFirstComponents = firstPoint.getFirstComponent() ==
secondPoint.getFirstComponent();
boolean sameSecondComponents = firstPoint.getSecondComponent() ==
secondPoint.getSecondComponent();
return sameFirstComponents || sameSecondComponents;
}
Finally, create a method which calculates if an arbitary number of points in a list are all between them horizontal or vertical (assuming if point A is horizontal with point B, then if point C is horizontal with B, so is with A).
Oveload that method since it does the same thing and the only thing changing are the parameters. (Note the use of the simple isHorizontal method from above)
public boolean isHorizontal(List<Point> points){
boolean allPointsHorizontal = true;
for (int i=0; i<points.size(); i++) {
boolean nextPointExists = i<points.size() - 1;
if (nextPointExists) {
Point current = points.get(i);
Point next = points.get(i+1);
allPointsHorizontal = allPointsHorizontal && isHorizontal(current,next);
if (!allPointsHorizontal)
return false;
}
}
return allPointsHorizontal;
}
You can have just one method as follows:
public boolean isHorizontalOrVertical(List<Point> points) {
if (points == null || points.size() < 2) {
throw new IllegalArgumentException("invalid number of points");
}
if (points.size() == 2) {
return points.get(0).getFirstComponent() == points.get(1).getFirstComponent()
|| points.get(0).getSecondComponent() == points.get(1).getSecondComponent();
}
Point start = points.get(0);
return points.stream()
.allMatch(p -> isHorizontalOrVertical(List.of(start, p)));
}
Note: If you are not using Java version >= 9, please use Arrays.asList instead of List.of.
The method could be implemented like this:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint, Point thirdPoint) {
return isHorizontalOrVertical(Arrays.asList(firstPoint, secondPoint, thirdPoint));
}
Your isHorizontalOrVertical(List<Point>) method will fail when the list is empty, and the call doesn't make much sense when the list has only one element.
I think a better way to do this is with two required parameters, plus a variadic parameter, so that callers must at least give 2 points.
private boolean are2PointsHorizontalOrVertical(Point firstPoint, Point secondPoint) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
}
public boolean arePointsHorizontalOrVertical(Point point1, Point point2, Point... rest) {
return are2PointsHorizontalOrVertical(point1, point2) &&
Arrays.stream(rest).allMatch(x -> are2PointsHorizontalOrVertical(point1, x));
}
This technically is still "one method" as far as the public interface is concerned. You can substitute the helper are2PointsHorizontalOrVertical back into the public method if you really want, but I don't see any benefit in doing that.
Actually, you can have only one method:
public boolean isHorizontalOrVertical(Point firstPoint, Point secondPoint, Point... others) {
// check firstPoint, secondPoint for null is ommited
if (others == null || others.length == 0) {
return firstPoint.getFirstComponent() == secondPoint.getFirstComponent()
|| firstPoint.getSecondComponent() == secondPoint.getSecondComponent();
} else {
// First, create a stream with second point + others elements
// then match against the first point
return Stream.of(new Point[]{secondPoint}, others).flatMap(e -> Stream.of(e))
.allMatch(p -> isHorizontalOrVertical(firstPoint, p));
}
}

How to check all members of an array

I am writing a text-based survival simulator that uses an array of Entitys. The Entity class contains data about each entity, such as energy, hydration, and morale. I'm starting to wrap up the project but I have a problem. In order to write a checkStatus() method, I need to have an if statement that checks for Entity[].isAlive on all entities, even if I don't know how long the array is. In short, how can I use an if statement to check for the value of all members of an array? I know I will probably have to use a for loop to iteratively check the members, with the array.getLength. So far I can only check variables in single classes. I have seen similar questions but they don't quite get what I'm looking for.
P.S. I'm using basic Java, with no frameworks or libraries.
Pseudo-code that demonstrates what I'm looking for
if Entity[ALL-MEMBERS].isAlive {
gameOver = true;
}
Java 6, 7, and 8:
public boolean areAllAlive(Entity[] entities) {
if(entities == null || entities.length == 0) {
return false; //?
}
for(Entity e : entities) {
if(!e.isAlive()) {
return false;
}
}
return true;
}
Java 8, using streams/functions:
public boolean areAllAlive(Entity[] entities) {
if(entities == null || entities.length == 0) {
return false; //?
}
return Arrays.stream(entities).allMatch(e -> e.isAlive());
}
First, since you probably don't know the number of Entities you are going to use before hand an ArrayList is probably a better choice. Then yes, you should use an enhanced for loop:
List<Entity> list = new ArrayList<>();
public void addEntities(){
//add Entities here
}
public boolean ifAlive(){
for (Entity e: list){
if (!e.isAlive()){
return false;
}
}
return true;
}
or something like that.
Assuming array is your entity's array, try this.:
for (int i = 0; i < array.length; i++) {
Entity entity = array[i];
if (entity.isAlive) {
gameOver = true;
//your code here
}
}

Best practice : get deep value of an object

Often in java I have to get a value of a property of an object which is deep in this object. For example, if I'm sure that all my sub-objects are not null, I can do that :
public function getDeepValue(A a) {
String value = a.getB().getC().getListeD().get(0).getE().getValue();
return value;
}
But in case of sub objects of the parent can be null, I have to test every object.
To do that, I see 2/3 solutions :
First, step by step :
public function getDeepValue(A a) {
if(a == null){
return null;
}
B b = a.getB();
if(b == null) {
return null;
}
C c = b.getC();
if(c == null){
return null;
}
List<D> ds = c.getListeD();
if(ds == null || ds.size() == 0){
return null;
}
D d = ds.get(0);
if(d == null) {
return null;
}
E e = d.getE()
if(e == null){
return null;
}
return e.getValue();
}
Second, test all in one if block, soooo dirty :
public function getDeepValue(A a) {
if(a != null && a.getB() != null && a.getB().getC() != null && a.getB().getC().getListeD() != null && a.getB().getC().getListeD().size() > 0 && a.getB().getC().getListeD().get(0) != null && a.getB().getC().getListeD().get(0).getE() != null){
return a.getB().getC().getListeD().get(0).getE().getValue();
}
return null;
}
Third solution, using a try catch block :
public function getDeepValue(A a) {
try {
return a.getB().getC().getListeD().get(0).getE().getValue();
} catch(NullPointerException e) {
return null;
} catch(IndexOutOfBoundsException e) {
return null;
}
}
Solution 1 seems not too bad but needs a lot of code. It is generally the solution I use.
Solution 2 is for me really dirty...
In paper, I realy like solution 3, but is it a good solution in term of performances ?
Is there any others acceptables solutions ?
Thanks for help, I hope my english is not too bad..
Regards
Solution #3 looks simple, but it can potentially hide a whole host of problems. It might be an adequate solution if you have full access to all of the classes in the chain and you know what's going on in each method and you can guarantee those methods won't cause problems with your try/catch and you're never going to change them... that's a lot of conditions to make it a worthwhile solution, but I can conceive that it's possibly a useful sufficient one.
Solution #2 looks horrid to me, especially if one or more of the get methods is a bottleneck (such as a slow database query or using a blocking network connection). The earlier in the chain such a potential bottleneck, the worse it would potentially be, as you're calling it over and over again. This of course depends on the implementation of the methods in question (even if one of them is slow, the result could be cached, for example), but you shouldn't need to know that in your client code. Even with efficient or trivial implementations, you've still got the overhead of repeated method calls you oughtn't need.
Solution #1 is the best of the three, but it's likely not the best possible. This solution takes more lines of code than the other two, but it doesn't repeat itself and it isn't going to be tripped up by the implementations of the other methods. (Note: If you do not have access to the classes in the chain for refactoring, I would use this solution.)
A better solution than #1 would be to refactor the classes so that the client code doesn't need to know about this chain at all. Something along these lines:
class Client {
public Mumble getDeepValue(A a) { return a == null ? null : a.getDeepValue(); }
}
class A {
private B b;
public Mumble getDeepValue() { return b == null ? null : b.getDeepValue(); }
}
class B {
private C c;
public Mumble getDeepValue() { return c == null ? null : c.getDeepValue(); }
}
class C {
private List<D> ds;
public Mumble getDeepValue() {
D d = ds == null || ds.size() == 0 ? null : ds.get(0);
return d == null ? null : d.getDeepValue();
}
}
class D {
private E e;
public Mumble getDeepValue() { return e == null ? null : e.getMumble(); }
}
class E {
private Mumble m;
public Mumble getMumble() { return m; }
}
As you can see, the longest chain any of these classes has is to access the public members of an element of a collection that is a private member of the class. (Essentially ds.get(0).getDeepValue()) The client code doesn't know how deep the rabbit hole goes, only that A exposes a method which returns a Mumble. Client doesn't even need to know that the classes B, C, D, E, or List exist anywhere!
Additionally, if I were designing this system from the ground up, I would take a good long look at whether it could be restructured such that the actual Mumble object wasn't so deep. If I could reasonably get away with storing the Mumble within A or B, I'd recommend doing it. Depending on the application, that may not be possible however.
in terms of performance solution 3 is the best one. In addition It is neat and easy to understand , For example looking at a loop example:
int[] b = somevalue;
for(int i=0;i<b.length;i++){
//do something
}
in this case for every iteration we execute the condition. However, there is another approach for it which uses try and catch
int[] b = somevalue;
try{
for(int i=0;;i++){
//do something
}
}catch(IndexOutOfBoundException e){
// do something
}
on the second solution,the loop keeps going until we reach the end of the loop which then it throws IndexOutOfBoundException as soon as we reach the end of the array. meaning we don't check for the condition no more. thus faster.

while-else-loop

Of course this is an impossible statement in java (to-date), however ideally I would like to implement it as it is at the heart of many iterations. For example the first multiple times it is called I'm doing it 650,000+ times when it is creating the ArrayList.
Unfortunately the reality is that my actual code does not have the set inside the else loop; thus it will pass over both the add and then the set commands and wasting time.
After that I have it also in another loop where it is only performing the set as the data is already created and this is multi-nested with in many others so it is a lengthy process.
ArrayList<Integer> dataColLinker = new java.util.ArrayList<Integer>();
...
...
public void setLinkerAt( int value, int rowIndex) {
...
while(rowIndex >= dataColLinker.size()) {
dataColLinker.add(value);
} else {
dataColLinker.set(rowIndex, value);
}
Any ideas or theories?
I'm unsure about speeds in java when it comes to if statements and ArrayList commands and so on
Am I missing something?
Doesn't this hypothetical code
while(rowIndex >= dataColLinker.size()) {
dataColLinker.add(value);
} else {
dataColLinker.set(rowIndex, value);
}
mean the same thing as this?
while(rowIndex >= dataColLinker.size()) {
dataColLinker.add(value);
}
dataColLinker.set(rowIndex, value);
or this?
if (rowIndex >= dataColLinker.size()) {
do {
dataColLinker.add(value);
} while(rowIndex >= dataColLinker.size());
} else {
dataColLinker.set(rowIndex, value);
}
(The latter makes more sense ... I guess). Either way, it is obvious that you can rewrite the loop so that the "else test" is not repeated inside the loop ... as I have just done.
FWIW, this is most likely a case of premature optimization. That is, you are probably wasting your time optimizing code that doesn't need to be optimized:
For all you know, the JIT compiler's optimizer may have already moved the code around so that the "else" part is no longer in the loop.
Even if it hasn't, the chances are that the particular thing you are trying to optimize is not a significant bottleneck ... even if it might be executed 600,000 times.
My advice is to forget this problem for now. Get the program working. When it is working, decide if it runs fast enough. If it doesn't then profile it, and use the profiler output to decide where it is worth spending your time optimizing.
I don't see why there is a encapsulation of a while...
Use
//Use the appropriate start and end...
for(int rowIndex = 0, e = 65536; i < e; ++i){
if(rowIndex >= dataColLinker.size()) {
dataColLinker.add(value);
} else {
dataColLinker.set(rowIndex, value);
}
}
boolean entered = false, last;
while (( entered |= last = ( condition ) )) {
// Do while
} if ( !entered ) {
// Else
}
You'r welcome.
Wrap the "set" statement to mean "set if not set" and put it naked above the while loop.
You are correct, the language does not provide what you're looking for in exactly that syntax, but that's because there are programming paradigms like the one I just suggested so you don't need the syntax you are proposing.
Java does not have this control structure.
It should be noted though, that other languages do.
Python for example, has the while-else construct.
In Java's case, you can mimic this behaviour as you have already shown:
if (rowIndex >= dataColLinker.size()) {
do {
dataColLinker.add(value);
} while(rowIndex >= dataColLinker.size());
} else {
dataColLinker.set(rowIndex, value);
}
This while else statement should only execute the else code when the condition is false, this means it will always execute it. But, there is a catch, when you use the break keyword within the while loop, the else statement should not execute.
The code that satisfies does condition is only:
boolean entered = false;
while (condition) {
entered = true; // Set it to true stright away
// While loop code
// If you want to break out of this loop
if (condition) {
entered = false;
break;
}
} if (!entered) {
// else code
}
Assuming you are coming from Python and accept this as the same thing:
def setLinkerAt(value, rowIndex):
isEnough = lambda i: return i < dataColLinker.count()
while (not isEnough(rowIndex)):
dataColLinker.append(value)
else:
dataColLinker[rowIndex] = value
The most similar I could come up with was:
public void setLinkerAt( int value, int rowIndex) {
isEnough = (i) -> { return i < dataColLine.size; }
if(isEnough()){
dataColLinker.set(rowIndex, value);
}
else while(!isEnough(rowInex)) {
dataColLinker.add(value);
}
Note the need for the logic, and the reverse logic. I'm not sure this is a great solution (duplication of the logic), but the braceless else is the closest syntax I could think of, while maintaining the same act of not executing the logic more than required.

Is there any appreciable difference between if and if-else?

Given the following code snippets, is there any appreciable difference?
public boolean foo(int input) {
if(input > 10) {
doStuff();
return true;
}
if(input == 0) {
doOtherStuff();
return true;
}
return false;
}
vs.
public boolean foo(int input) {
if(input > 10) {
doStuff();
return true;
} else if(input == 0) {
doOtherStuff();
return true;
} else {
return false;
}
}
Or would the single exit principle be better here with this piece of code...
public boolean foo(int input) {
boolean toBeReturned = false;
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
}
return toBeReturned;
}
Is there any perceptible performance difference? Do you feel one is more or less maintainable/readable than the others?
With the second example you state very clearly that both conditions are mutually exclusive.
With the first one, it is not so clear, and in the (unlikely) event that an assignment to input is added between both ifs, the logic would change.
Suppose someone in the future adds input = 0 before the second if.
Of course this is unlikely to happen, but if we are talking about maintainability here, if-else says clearly that there are mutually exclusive conditions, while a bunch of ifs don't, and they are not so dependent between each other as are if-else blocks.
edit:Now that I see, in this particular example, the return clause forces the mutual exclusivity, but again, we're talking about maintainability and readability.
Anyway, about performance, if this is coded in Java you shouldn't care for performance of a couple of if blocks, if it were embedded C in a really slow hardware, maybe, but certainly not with java.
Use whatever form best describes your intent.
Do not follow the single exit principle if things are this simple, though--it just makes it more confusing.
In the first:
somebody eventually, by some strange reason and when you're not looking will add some add statement that will make this method fail under certain strange conditions, everybody ( or worst, one single person ) will spend 4 hrs. watching the source code and debugging the application to finally found there was something in the middle.
The second is definitely better, not only it prevents this scenario, but also helps to clearly state , it this or this other no more.
If all the code we write within an if where 10 lines long at most, this wouldn't matter really, but unfortunately that's not the case, there exists other programmers which by some reason think that a if body should be > 200 lines long... anyway.
I don't like the third, it forces me to look for the return variable, and it's easier to find the return keyword
About speed performance, they are ( almost ) identical. Don't worry about that.
In your last example, don't do this:
public boolean foo(int input) {
boolean toBeReturned = false;
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
}
return toBeReturned;
}
but this (notice the use of Java's final):
public boolean foo(int input) {
final boolean toBeReturned; // no init here
if(input > 10) {
doStuff();
toBeReturned = true;
} else if(input == 0) {
doOtherStuff();
toBeReturned = true;
} else {
toBeReturned = false;
}
return toBeReturned;
}
By doing so you make your intend clear and this is a godsend for IDEs supporting "programming by intention" (there's no need to "compile" to see potential errors, even on a partial AST, a good IDE can examine incomplete source in real-time and give you instant warnings).
This way you are sure not to forget to initialize your return value. This is great if later on you decide that after all you need another condition.
I do this all the time and even moreso since I started using IntelliJ IDEA (version 4 or so, a long time ago) and this has saved me so many silly distraction mistakes...
Some people will argue that this is too much code for such a simple case but that's entirely missing the point: the point is to make the intent clear so that the code reads easily and can be easily extended later on, without accidentally forgetting to assign toBeReturned and without accidentally forgetting to return from a later clause you may add.
Otherwise, if "conciseness" was the name of the game, then I'd write:
public boolean foo(int a) {
return a > 10 ? doStuff() : a == 0 ? doOtherStuff() : false;
}
Where both doStuff and doOtherStuff would return true.
Semantically — no. Performance-wise this depends on compiler, i.e. whether it can spot that both conditions cannot be true at once. I'd bet standard Sun compiler can. Whether to use single exit principle depends on tastes. I personally hate it.
Version #1 and #2 may be faster than #3, but I suppose the performance difference is minimal. I would rather focus on readability.
Personally, I would never use version #2. Between #1 and #3, I would choose the one that yields the most readable code for the case in question. I don't like many exit points in my methods, because it makes the code hard to analyze. However, there are cases where the flow becomes clearer when we exit immediately for some special cases, and continue with the main cases.
Think of this case when the two examples won't be similar:
public boolean foo(int input) {
if (input > 10) {
// doStuff();
return true;
}
System.out.println("do some other intermediary stuff");
if (input == 0) {
// doOtherStuff();
return true;
}
return false;
}
vs.
public boolean foo(int input) {
if (input > 10) {
// doStuff();
return true;
}
//System.out.println("doing some intermediary stuff... doesn't work");
else if (input == 0) {
// doOtherStuff();
return true;
} else {
return false;
}
return false;
}
The first approach is probably more flexible, but both formulas have their use in different circumstances.
Regarding performance, I think the differences are to small to be taken in consideration, for any regular java application, coded by sane programmers :).
In your case the second if would only get called if the first if failed so it's less important here but if your first if did something and didn't return, the second if (which would then always be false) would still be tested unless it was in an else-if.
In other words, there are cases where the difference between if-else-if and if-if matters, but this isn't one of them.
Example: Try this and then try it after removing the else. You get two different outputs:
int someNumber = 1;
if(someNumber < 5)
{
someNumber += 5;
Console.WriteLine("First call.");
}
else if(someNumber >= 5)
{
Console.WriteLine("Second call.");
}
Between the first and second snippets, there's really no difference. However the third snippet is quite inefficient. Because you wait to return control of the program to the caller until the last line of code in the method, you waste processing power/memory whereas the first two code snippets return control as soon as it determines one of the conditions to be true.

Categories