tutorial ejemplo java optimization coding-style static

ejemplo - text box java



¿Cuál es la ganancia de declarar un método como estático? (9)

Hace poco estuve revisando mis advertencias en Eclipse y me encontré con esta:

Le dará una advertencia al compilador si el método puede declararse como estático.

[edit] Cita exacta dentro de la ayuda de Eclipse, con énfasis en privado y final:

Cuando está habilitado, el compilador emitirá un error o una advertencia para los métodos que son privados o finales y que se refieren solo a los miembros estáticos.

Sí, sé que puedo desactivarlo, pero quiero saber la razón para activarlo .

¿Por qué sería bueno declarar que todos los métodos posibles son estáticos?

¿Esto le dará algún beneficio de rendimiento? (en un dominio móvil)

Señalando un método como estático, supongo que muestra que no utiliza ninguna variable de instancia por lo tanto, ¿podría moverse a una clase de estilo utils?

Al final del día, ¿debería apagar esto? ¿Ignorar? ¿O debería arreglar las más de 100 advertencias que me ha dado?

¿Crees que esto solo son palabras clave adicionales que ensucian el código, ya que el compilador simplemente incluirá estos métodos de todos modos? (Algo así como que no declaras todas las variables que puedes, pero podrías ).


Bueno, la documentación de Eclipse dice acerca de la advertencia en cuestión:

El método puede ser estático

Cuando está habilitado, el compilador emitirá un error o una advertencia para los métodos que son privados o finales y que se refieren solo a los miembros estáticos

Creo que prácticamente lo dice todo. Si el método es privado y final y solo se refiere a miembros estáticos, el método en cuestión también podría declararse estático y, con esto, dejar en claro que solo tenemos la intención de acceder a contenido estático desde él.

Honestamente, no creo que haya ninguna otra razón misteriosa detrás de esto.


Cada vez que escribe un método, cumple un contrato en un ámbito determinado. Cuanto más estrecho es el alcance, menor es la probabilidad de que escriba un error.

Cuando un método es estático, no puede acceder a miembros no estáticos; por lo tanto, su alcance es más estrecho. Entonces, si no necesita y nunca necesitará (incluso en subclases) miembros no estáticos para cumplir con su contrato, ¿por qué dar acceso a estos campos a su método? Declarar el método como static en este caso permitirá al compilador verificar que no use miembros que no tiene la intención de usar.

Y, además, ayudará a las personas que leen su código a comprender la naturaleza del contrato.

Es por eso que se considera bueno declarar un método static cuando en realidad está implementando un contrato estático.

En algunos casos, su método solo significa algo relativo a una instancia de su clase, y sucede que su implementación en realidad no utiliza ningún campo o instancia no estática. En tales casos, no marcaría el método static .

Ejemplos de donde no usaría la palabra clave static :

  • Un enlace de extensión que no hace nada (pero podría hacer algo con los datos de instancia en una subclase)
  • Un comportamiento predeterminado muy simple destinado a ser personalizable en una subclase.
  • Implementación del controlador de eventos: la implementación variará con la clase del controlador de eventos pero no usará ninguna propiedad de la instancia del controlador de eventos.

De las pautas de rendimiento de Android:

Prefiere Static Over Virtual Si no necesita acceder a los campos de un objeto, haga que su método sea estático. Las invocaciones serán entre un 15% y un 20% más rápidas. También es una buena práctica, ya que puede observar a partir de la firma del método que llamar al método no puede alterar el estado del objeto.

http://developer.android.com/training/articles/perf-tips.html#PreferStatic


Los métodos que puede declarar como estáticos son los que no requieren creación de instancias, como

public class MyClass { public static string InvertText(string text) { return text.Invert(); } }

A continuación, puede llamar en cualquier otra clase sin instanciar esa clase.

public class MyClassTwo { public void DoSomething() { var text = "hello world"; Console.Write(MyClass.InvertText(text)); } }

... Pero eso es algo que probablemente ya sabes. No le proporciona ningún beneficio real en sí mismo, aparte de dejar en claro que el método no utiliza variables de instancia.

En otras palabras, puede con seguridad simplemente apagarlo por completo. Si sabe que nunca usará un método en otras clases (en cuyo caso debería ser solo privado), no necesita que sea estático.


Me faltaban algunos números para las diferencias de velocidad. Así que traté de compararlos, lo que resultó no ser tan fácil: ¿el bucle de Java se vuelve más lento después de algunas corridas / falla de JIT?

Finalmente utilicé Caliper y los resultados son los mismos que cuando ejecuté mis pruebas a mano:

No hay diferencia medible para llamadas estáticas / dinámicas. Al menos no para Linux / AMD64 / Java7.

Los resultados de Caliper están aquí: 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

y mis propios resultados son:

Static: 352 ms Dynamic: 353 ms Static: 348 ms Dynamic: 349 ms Static: 349 ms Dynamic: 348 ms Static: 349 ms Dynamic: 344 ms

La clase de prueba Caliper fue:

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; } }

Y mi propia clase de prueba fue:

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; } }


No hay un concepto con optimización aquí.

Un método static es static porque usted declara explícitamente que el método no depende de ninguna instancia de la clase adjunta simplemente porque no lo necesita. Entonces, esa advertencia de Eclipse, como se indica en la documentación:

Cuando está habilitado, el compilador emitirá un error o una advertencia para los métodos que son privados o finales y que se refieren solo a los miembros estáticos.

Si no necesita ninguna variable de instancia y su método es privado (no se puede llamar desde el exterior) o es final (no se puede anular), entonces no hay ninguna razón para dejar que sea un método normal en lugar de uno estático. Un método estático es intrínsecamente más seguro incluso porque se le permite hacer menos cosas con él (no necesita ninguna instancia, no tiene ningún objeto implícito).


No tengo información sobre el rendimiento, supongo que es marginalmente mejor a lo sumo, ya que el código no necesita hacer un despacho dinámico basado en el tipo.

Sin embargo, un argumento mucho más sólido contra la refactorización en métodos estáticos es que actualmente el uso de estática se considera una mala práctica. Los métodos / variables estáticos no se integran bien en un lenguaje orientado a objetos y también son difíciles de probar correctamente. Esta es la razón por la cual algunos lenguajes más nuevos renuncian por completo al concepto de métodos / variables estáticos, o intentan internalizarlo en el lenguaje de una manera que se desempeña mejor con OO (por ejemplo, Objetos en Scala).

La mayoría de las veces, necesita métodos estáticos para implementar funciones que solo usan parámetros como entrada y producen una salida usando eso (por ejemplo, funciones de utilidad / auxiliar). En los idiomas modernos, hay un concepto de función de primera clase que permite eso, por lo tanto estático no es necesario. Java 8 tendrá expresiones lambda integradas, por lo que ya nos estamos moviendo en esta dirección.


Vea la respuesta de Samuel sobre cómo cambia el alcance del método. Supongo que este es el aspecto principal de hacer un método estático.

También preguntaste sobre el rendimiento:

Puede haber una pequeña ganancia de rendimiento, porque una llamada a un método estático no necesita la referencia implícita "this" como parámetro.

Sin embargo, este impacto en el rendimiento es muy pequeño. Por lo tanto, se trata del alcance.


1. El método de declaración static brinda un pequeño beneficio de rendimiento, pero lo que es más útil, permite usarlo sin tener una instancia de objeto a la mano (piénsese, por ejemplo, en el método de fábrica o obtenga un singleton). También sirve el propósito documental de contar la naturaleza del método. Este propósito documental no debe ignorarse, ya que da una pista inmediata sobre la naturaleza del método para los lectores del código y los usuarios de la API y también sirve como una herramienta de pensamiento para el programador original: ser explícito sobre el significado previsto ayuda también piensas correctamente y produces un código de mejor calidad (creo basado en mi experiencia personal, pero las personas son diferentes). Por ejemplo, es lógico y por lo tanto deseable distinguir entre métodos que operan en un tipo y métodos que actúan en una instancia del tipo (como lo señaló Jon Skeet en su comentario a una pregunta C # ).

Otro caso de uso de métodos static es imitar la interfaz de programación de procedimientos. Piensa en la clase java.lang.System.println() y los métodos y atributos en ella. La clase java.lang.System se utiliza como un espacio de nombre de agrupación en lugar de como un objeto instanciable.

2. ¿Cómo puede saber Eclipse (o cualquier otra entidad programada u otro tipo de entidad biodegradable o no biocomponible) qué método podría declararse como estático? Incluso si una clase base no está accediendo a variables de instancia o llamando a métodos no estáticos, el mecanismo de herencia puede cambiar las cosas. Solo si el método no puede ser anulado heredando la subclase, podemos afirmar con 100% de certeza que el método realmente puede declararse static . Anular un método es imposible exactamente en los dos casos de ser

  1. private (ninguna subclase puede usarlo directamente y ni siquiera lo sabe en principio), o
  2. final (incluso si es accesible por la subclase, no hay forma de cambiar el método para referirse a los datos o funciones de la instancia).

De ahí la lógica de la opción Eclipse.

3. El póster original también pregunta: " Señalar un método como estático, supongo que muestra que no se usa ninguna variable de instancia, por lo tanto, se podría mover a una clase de estilo utils ". Este es un muy buen punto. A veces, este tipo de cambio de diseño está indicado por la advertencia.

Es una opción muy útil, que personalmente me aseguraré de habilitar, si fuera a usar Eclipse y fuera a programar en Java.