StackTips
 14 minutes

Code optimization tips for java

By Editorial @stacktips, On Sep 17, 2023 Java 2.31K Views

In this section we will see some of the useful tips for java programmers.

When not to Optimize

  • Optimization is a good way to introduce bugs
  • Some techniques decrease the portability of your code
  • We can expend a lot of effort for little or no results

We can distinguish between different types of optimization

  • Optimizing for speed
  • Optimizing for maintainability
  • Optimizing for size

1. Unroll Loops to Optimize Your Code

A compiler can automatically optimize the code by unrolling loops. Consider this code

int buff = new int[3];
for (int i =0; i<3;i++)
{
buff[i] = 0;
}

On every iteration, the loop assigns a value to the next array element. However,precious CPU time is also wasted on testing and incrementing the loop counter,and performing a jump statement. To avoid this overhead, the compiler can unroll the loop into a sequence of three assignment statements

buff[0] = 0;
buff[1] = 0;
buff[2] = 0;

This way, you avoid the unnecessary overhead of a loop. Note, however,that the compiler applies this optimization automatically; you shouldn’t do it yourself.

2. Use return statements out of switch blocks

The break statements are necessary in each branch in a switch statement because otherwise the flow of execution “falls through” to the next

case. switch (suit) {

case CLUBS: {
----
----
stmts; } return "Clubs";

case DIAMONDS: {
----
----
stmts;
}
return "Diamonds";

case HEARTS: {
----
-----
stmts;
}

return "Hearts";

case SPADES:
{
-------------
-------------
stmts;
}
return "Spades";

default:
{
-------------
-------------
stmts;
}
return "Not a valid suit";
}

return statement saves 3 bytes.

In this case we don’t need break statements because the return statements cause the flow of execution to return to the caller instead of falling through to the next case. In general it is good style to include a default case in every switch statement, to handle errors or unexpected values

3. Eliminate Common Subexpressions

Before (Eliminate):

double x = d * (lim/max) * sx;
double y = d *(lim/max) * sy;

After (Eliminate):

double depth = d * (lim/max); doublex = depth * sx;
double y = depth * sy;

4. Avoid String constant

System.out.println statements they are bulky and apart from testing purposes aren’t going to do much on a cell phone. For Ex: System.out.println(“Collide”); System.out.println(“intBallX”+ intBallX);

5. Division is slower than multiplication

Division is slower than multiplication, so multiply by the inverse instead of dividing. There are also some optimizations you can perform when using a Fixed Point math library.First, if you’re doing a lot of division by a single number, you should instead work out the inverse of that number and perform a multiplication. Multiplication Is slightly quicker than division. So instead of…

int fpP = FP.Div( fpX, fpD );
int fpQ = FP.Div( fpY, fpD );
int fpR = FP.Div( fpZ, fpD );

…you should rewrite it like this:

int fpID = FP.Div( 1, fpD);
int fpP = FP.Mul( fpX, fpID );
int fpQ = FP.Mul( fpY, fpID );
int fpR = FP.Mul( fpZ, fpID );

If you’re performing hundreds of divisions every frame, this will help.

6. Avoid typecasting

Avoid typecasting, use type integers instead. For example, you may find that the multiplication method has to cast both ints to longs and then back to an int:

Public static final int Mul (int x, int y) {

long z = (long) x * (long) y;
return ((int) (z >> 16));
}

Those casts take time. Collision detection using bounding circles or spheres involves adding the squares of ints together. That can generate some bignumbers that might overflow the upper bound of your int Fixed Point data type.To avoid this, you could write your own square function that returns a long:

public static final long Sqr (int x) {
long z = (long) x;
z *= z;
return (z >> 16);
}

This optimized method avoids a couple of casts

7. Carefully evaluate coding alternatives

A switch statement is an alternative to a chained conditional that is syntactically prettier and often more efficient. It looks like this:

switch (symbol) {
case '+':
perform_addition ();
break;
case '*':
perform_multiplication ();
break;
default:
System.out.println("I only know how to perform addition and multiplication");
break;
}

This switch statement is equivalent to the following chained conditional:

if (symbol == '+') {
perform_addition ();
} else if (symbol == '*') {
perform_multiplication ();
} else {
System.out.println("I only know how to perform addition and multiplication");
}

It can reduce 40 bytes.

8. Null Out the Old References

Be sure to help garbage collector to do its work by setting object reference to null whenever you are finished with themFor Example: You might define a deinitialize method for a class in order to explicitly clear out its members

public class myClass {

private SomeObject someObject;

public myClass(Object obj)
{
--------------------
}

public void deinitialize()
{
someObject = null;
}
}

By clearing out object references, you make it easier for the garbage collector to find and reclaim and unreferenced objects.This technique is simple and does not add too much code to your classes.

The garbage collector works automatically, whether you request it to or not. However, it is possible to make a garbage collector request, by invoking the System.gc() method. When garbage collector starts its work, you may have a short pause in the application’s execution. This is the reason why you should only invoke the System.gc() method at the right time, such as before performing a huge task or when the application is idle,waiting for user’s input.

stacktips avtar

Editorial

StackTips provides programming tutorials, how-to guides and code snippets on different programming languages.