I\'ve recently been looking through my warnings in Eclipse and come across this one:
The methods you can declare as static are the ones that don't require instantiation, such as
public class MyClass
{
public static string InvertText(string text)
{
return text.Invert();
}
}
Which you can then in return call out in any other class without instanciating that class.
public class MyClassTwo
{
public void DoSomething()
{
var text = "hello world";
Console.Write(MyClass.InvertText(text));
}
}
... But that's something you probably already know. It doesn't give you any real benefits per se, other than making it more clear that the method doesn't use any instance variables.
In other words, you can most safely just turn it off completely. If you know you will never use a method in other classes (in which case it should just be private), you don't need it to be static at all.
Well, the Eclipse documentation says about the warning in question:
Method can be static
When enabled, the compiler will issue an error or a warning for methods which are private or final and which refer only to static members
I think it pretty much says it all. If the method is private and final and only refers to static members, the method in question might just as well be declared static and by this, make evident that we only intend to access static content from it.
I honestly don't think there is any other mysterious reason behind it.
I was missing some numbers for the speed differences. So I tried to benchmark them which turned out to be not so easy: Java loop gets slower after some runs / JIT's fault?
I finally used Caliper and the results are the same as running my tests by hand:
There is no measurable difference for static/dynamic calls. At least not for Linux/AMD64/Java7.
The Caliper Results are here: https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplusPercent,scenario.vmSpec.options.CMSLargeSplitSurplusPercent,scenario.vmSpec.options.CMSSmallCoalSurplusPercent,scenario.vmSpec.options.CMSSmallSplitSurplusPercent,scenario.vmSpec.options.FLSLargestBlockCoalesceProximity,scenario.vmSpec.options.G1ConcMarkStepDurationMillis
and my own results are:
Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms
The Caliper Test class was:
public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {
public static void main( String [] args ){
CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
}
public int timeAddDynamic( long reps ){
int r=0;
for( int i = 0; i < reps; i++ ) {
r |= addDynamic( 1, i );
}
return r;
}
public int timeAddStatic( long reps ){
int r=0;
for( int i = 0; i < reps; i++ ) {
r |= addStatic( 1, i );
}
return r;
}
public int addDynamic( int a, int b ){
return a+b;
}
private static int addStatic( int a, int b ){
return a+b;
}
}
And my own Test class was:
public class TestPerformanceOfStaticVsDynamicCalls {
private static final int RUNS = 1_000_000_000;
public static void main( String [] args ) throws Exception{
new TestPerformanceOfStaticVsDynamicCalls().run();
}
private void run(){
int r=0;
long start, end;
for( int loop = 0; loop<10; loop++ ){
// Benchmark
start = System.currentTimeMillis();
for( int i = 0; i < RUNS; i++ ) {
r += addStatic( 1, i );
}
end = System.currentTimeMillis();
System.out.println( "Static: " + ( end - start ) + " ms" );
start = System.currentTimeMillis();
for( int i = 0; i < RUNS; i++ ) {
r += addDynamic( 1, i );
}
end = System.currentTimeMillis();
System.out.println( "Dynamic: " + ( end - start ) + " ms" );
// Do something with r to keep compiler happy
System.out.println( r );
}
}
private int addDynamic( int a, int b ){
return a+b;
}
private static int addStatic( int a, int b ){
return a+b;
}
}