paso - metodos con parametros en java ejemplos
¿Cuándo se debe usar el final para los parámetros del método y las variables locales? (16)
He encontrado un par de referencias ( por ejemplo ) que sugieren usar el final
tanto como sea posible y me pregunto qué tan importante es eso. Esto se debe principalmente al contexto de los parámetros del método y las variables locales, no a los métodos o clases finales. Para las constantes, tiene sentido obvio.
Por un lado, el compilador puede hacer algunas optimizaciones y hace que la intención del programador sea más clara. Por otro lado, agrega verbosidad y las optimizaciones pueden ser triviales.
¿Es algo que debería hacer un esfuerzo para recordar hacer?
¿Es algo que debería hacer un esfuerzo para recordar hacer?
No, si está utilizando Eclipse, porque puede configurar una Acción de guardado para agregar automáticamente estos modificadores finales . Entonces obtienes los beneficios por menos esfuerzo.
Bueno, todo esto depende de tu estilo ... si te gusta ver el final cuando no estarás modificando la variable, entonces úsalo. Si no te gusta verlo ... entonces déjalo fuera.
Personalmente, me gusta la menor verborrea posible, por lo que tiendo a evitar el uso de palabras clave adicionales que no son realmente necesarias.
Aunque prefiero los lenguajes dinámicos, así que probablemente no sea una sorpresa. Me gusta evitar la verborrea.
Por lo tanto, yo diría que simplemente escoja la dirección hacia la que se inclina y simplemente continúe con ella (en cualquier caso, trate de ser consecuente).
Como nota al margen, he trabajado en proyectos que usan y no usan dicho patrón, y no he visto diferencia en la cantidad de errores o fallas ... No creo que sea un patrón que genere un gran impacto. mejore su conteo de errores o cualquier otra cosa, pero nuevamente es estilo, y si le gusta expresar el intento de que no lo modifique, siga adelante y úselo.
En primer lugar, la palabra clave final se usa para hacer que una variable sea constante. Constante significa que no cambia. Por ejemplo:
final int CM_PER_INCH = 2.54;
Declararía la variable final porque un centímetro por pulgada no cambia.
Si intenta anular un valor final, la variable es lo que se declaró primero. Por ejemplo:
final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"
Hay un error de compilación que es algo así como:
local variable is accessed from inner class, must be declared final
Si su variable no puede declararse definitiva o si no desea declararla definitiva, intente esto:
final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);
Esto se imprimirá:
Hello World!
A String
Es útil en los parámetros para evitar cambiar el valor del parámetro por accidente e introducir un error sutil. Utilizo para ignorar esta recomendación pero después de pasar unas 4 horas. en un método horrible (con cientos de líneas de código y múltiples fors, if anidados y todo tipo de malas prácticas) te recomendaría que lo hicieras.
public int processSomethingCritical( final int x, final int y ){
// hundreds of lines here
// for loop here...
int x2 = 0;
x++; // bug aarrgg...
// hundreds of lines there
// if( x == 0 ) { ...
}
Por supuesto, en un mundo perfecto esto no sucedería, pero ... bueno ... a veces tienes que apoyar el código de otros. :(
Hay muchos usos para la variable final
. Aquí hay solo algunos
Constantes finales
public static class CircleToolsBetter {
public final static double PI = 3.141;
public double getCircleArea(final double radius) {
return (Math.pow(radius, 2) * PI);
}
}
Esto se puede usar luego para otras partes de sus códigos, o para acceder a otras clases, de esa manera si alguna vez cambia el valor, no tendría que cambiarlos uno por uno.
Variables finales
public static String someMethod(final String environmentKey) {
final String key = "env." + environmentKey;
System.out.println("Key is: " + key);
return (System.getProperty(key));
}
}
En esta clase, crea una variable final con ámbito que agrega un prefijo al parámetro environmentKey. En este caso, la variable final es final solo dentro del alcance de la ejecución, que es diferente en cada ejecución del método. Cada vez que se ingresa el método, se reconstruye el final. Tan pronto como se construye, no se puede cambiar durante el alcance de la ejecución del método. Esto le permite corregir una variable en un método por la duración del método. vea abajo:
public class FinalVariables {
public final static void main(final String[] args) {
System.out.println("Note how the key variable is changed.");
someMethod("JAVA_HOME");
someMethod("ANT_HOME");
}
}
Constantes finales
public double equation2Better(final double inputValue) {
final double K = 1.414;
final double X = 45.0;
double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;
if (result > 360) {
powInputValue = X * Math.sin(result);
} else {
inputValue = K * Math.sin(result); // <= Compiler error
}
Estos son especialmente útiles cuando tiene líneas muy largas de códigos, y generará un error de compilación para que no se ejecute en un error lógico / comercial cuando alguien accidentalmente cambie variables que no deberían modificarse.
Colecciones finales
Caso diferente cuando hablamos de Colecciones, necesitas establecerlas como no modificables.
public final static Set VALID_COLORS;
static {
Set temp = new HashSet( );
temp.add(Color.red);
temp.add(Color.orange);
temp.add(Color.yellow);
temp.add(Color.green);
temp.add(Color.blue);
temp.add(Color.decode("#4B0082")); // indigo
temp.add(Color.decode("#8A2BE2")); // violet
VALID_COLORS = Collections.unmodifiableSet(temp);
}
de lo contrario, si no lo configura como no modificable:
Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler
Las clases finales y los métodos finales no se pueden extender o sobrescribir, respectivamente.
EDITAR: PARA ABORDAR EL PROBLEMA DE LA CLASE FINAL EN RELACIÓN CON LA ENCAPSULACIÓN:
Hay dos formas de hacer una clase final. El primero es usar la palabra clave final en la declaración de clase:
public final class SomeClass {
// . . . Class contents
}
La segunda forma de hacer una clase final es declarar todos sus constructores como privados:
public class SomeClass {
public final static SOME_INSTANCE = new SomeClass(5);
private SomeClass(final int value) {
}
Marcarlo final le ahorra la molestia si descubre que es real una final, para demostrar que mira esta clase de prueba. se ve público a primera vista.
public class Test{
private Test(Class beanClass, Class stopClass, int flags)
throws Exception{
// . . . snip . . .
}
}
Desafortunadamente, dado que el único constructor de la clase es privado, es imposible extender esta clase. En el caso de la clase de prueba, no hay ninguna razón para que la clase sea final. La clase de prueba es un buen ejemplo de cómo las clases finales implícitas pueden causar problemas.
Por lo tanto, debe marcarlo como definitivo cuando implícitamente haga una clase final haciendo que su constructor sea privado.
He encontrado que los parámetros del método de marcado y los locales como final
son útiles como ayuda de refactorización cuando el método en cuestión es un lío incomprensible de varias páginas. Espolvoree el final
liberalmente, vea qué errores "no puede asignar a la variable final" que el compilador (o su IDE) arroja, y usted puede descubrir por qué la variable llamada "datos" termina nula a pesar de que varios comentarios (desactualizados) juran que no puede suceder
Luego puede corregir algunos de los errores al reemplazar las variables reutilizadas con nuevas variables declaradas más cercanas al punto de uso. Luego descubres que puedes envolver partes enteras del método en llaves de alcance, y de repente eres una llave IDE alejada de "Método de extracción" y tu monstruo se volvió más comprensible.
Si su método no es ya una ruina imposible de mantener, creo que puede ser valioso hacer cosas definitivas para desalentar a las personas a convertirlas en restos de naufragios; pero si se trata de un método breve (ver: no imposible de mantener), entonces corre el riesgo de agregar mucha verbosidad. ¡En particular, las firmas de función de Java son lo suficientemente difíciles como para caber en 80 caracteres como lo es sin agregar seis más por argumento!
Los beneficios de tiempo de desarrollo de "final" son al menos tan significativos como los beneficios de tiempo de ejecución. Le dice a los futuros editores del código algo sobre tus intenciones.
Marcar una clase "final" indica que no ha hecho un esfuerzo durante el diseño o la implementación de la clase para manejar la extensión con elegancia. Si los lectores pueden hacer cambios en la clase y desean eliminar el modificador "final", pueden hacerlo bajo su propio riesgo. Depende de ellos asegurarse de que la clase maneje bien la extensión.
Marcar una variable "final" (y asignarla en el constructor) es útil con la inyección de dependencia. Indica la naturaleza "colaboradora" de la variable.
Marcar un método "final" es útil en clases abstractas. Delinea claramente dónde están los puntos de extensión.
No queda claro a partir de la pregunta si esto es obvio, pero hacer que un parámetro de método final afecte solo al cuerpo del método. NO transmite ninguna información interesante sobre las intenciones del método al invocador. El objeto que se está pasando todavía puede mutarse dentro del método (las finales no son constelaciones), y el alcance de la variable está dentro del método.
Para responder a su pregunta precisa, no me molestaría en convertir una instancia o variable local (incluidos los parámetros del método) en definitiva a menos que el código lo requiera (p. Ej., Se hace referencia a la variable desde una clase interna) o aclarar alguna lógica realmente complicada.
Por ejemplo, las variables, las convertiría en definitivas si son lógicamente constantes.
Obsesionarse con:
- Campos finales: Marcar campos como finales los fuerza a establecerse para el final de la construcción, lo que hace que la referencia de campo sea inmutable. Esto permite la publicación segura de los campos y puede evitar la necesidad de sincronización en lecturas posteriores. (Tenga en cuenta que para una referencia de objeto, solo la referencia de campo es inmutable; las cosas a las que hace referencia el objeto pueden cambiar y eso afecta la inmutabilidad).
- Campos estáticos finales: aunque ahora utilizo las enumeraciones para muchos de los casos en los que solía usar campos finales estáticos.
Considere pero use juiciosamente:
- Clases finales: el diseño de Framework / API es el único caso donde lo considero.
- Métodos finales: básicamente lo mismo que las clases finales. Si está utilizando patrones de métodos de plantilla como locos y marcando cosas finales, probablemente dependa demasiado de la herencia y no lo suficiente en la delegación.
Ignore a menos que sienta anal:
- Parámetros del método y variables locales: RAREAMENTE hago esto en gran parte porque soy flojo y me parece que desordena el código. Admitiré por completo que marcar los parámetros y las variables locales que no voy a modificar es "correcto". Desearía que fuera el predeterminado. Pero no es así y el código me resulta más difícil de entender con las finales por todas partes. Si estoy en el código de otra persona, no voy a sacarlos, pero si estoy escribiendo un nuevo código, no los incluiré. Una excepción es el caso en el que debe marcar algo final para que pueda acceder desde dentro de una clase interna anónima.
Si está escribiendo una aplicación que alguien tendrá que leer el código después de, digamos, 1 año, entonces sí, use la variable final que no se debe modificar todo el tiempo. Al hacer esto, su código será más "auto-documentado" y también reducirá la posibilidad de que otros desarrolladores hagan cosas tontas como usar una constante local como una variable temporal local.
Si estás escribiendo un código desechable, entonces, no, no te molestes en identificar todas las constantes y hacer que sean definitivas.
Si tiene clases internas (anónimas) y el método necesita acceder a la variable del método contenedor, necesita tener esa variable como definitiva.
Aparte de eso, lo que has dicho es correcto.
Un poco de una compensación como usted menciona, pero prefiero el uso explícito de algo más que el uso implícito. Esto ayudará a eliminar cierta ambigüedad para los futuros mantenedores de código, incluso si es solo usted.
Una respuesta muy simple tenemos 3 casos con Final con variables, Final con métodos && Final con clases ...
1.Final con variable: no puedes asignar esta variable más de una vez.
2.Final con métodos: no puedes anular este método ...
3.Final con las clases: no se puede extender ninguna clase final
Usaré el final tanto como pueda. Si lo hace, se marcará si cambia involuntariamente el campo. También establecí los parámetros del Método en final. Al hacerlo, he capturado varios errores del código que he tomado cuando intentan ''establecer'' un parámetro olvidando que Java pasa por valor.
Use final
palabra clave final
para una variable si está convirtiendo esa variable en immutable
Al declarar la variable como definitiva, ayuda a los desarrolladores a descartar posibles problemas de modificación de variables en entornos de múltiples subprocesos.
Con la versión java 8, tenemos un concepto más llamado " effectively final variable
". Una variable no final puede aparecer como variable final.
las variables locales a las que se hace referencia desde una expresión lambda deben ser finales o efectivamente finales
Una variable se considera efectiva final si no se modifica después de la inicialización en el bloque local. Esto significa que ahora puede usar la variable local sin la palabra clave final dentro de una clase anónima o expresión lambda, siempre que sea efectivamente definitiva.
Hasta Java 7, no puede usar una variable local no final dentro de una clase anónima, pero desde Java 8 puede
Eche un vistazo a este article
Uso final
todo el tiempo para hacer que Java se base más en expresiones. Ver las condiciones de Java ( if,else,switch
) no se basan en expresiones, lo que siempre he odiado, especialmente si está acostumbrado a la programación funcional (es decir, ML, Scala o Lisp).
Por lo tanto, debe intentar siempre (en mi humilde opinión) usar variables finales cuando use condiciones.
Dejame darte un ejemplo:
final String name;
switch(pluginType) {
case CANDIDATE_EXPORT:
name = "Candidate Stuff";
break;
case JOB_POSTING_IMPORT:
name = "Blah";
break;
default:
throw new IllegalStateException();
}
Ahora si agrega otra declaración de case
y no establece el name
el compilador fallará. El compilador también fallará si no se divide en todos los casos (que se establece la variable). Esto le permite hacer que Java sea muy similar a las expresiones de let
de Lisp y lo hace para que su código no tenga indentaciones masivas (debido a las variables de alcance léxico).
Y como notó @Recurse (pero aparentemente -1 me) puedes hacer lo anterior sin hacer que String name
final
para obtener el error del compilador (que nunca dije que no pudieras) pero podrías hacer fácilmente que el error del compilador desaparezca. después de la instrucción switch que arroja la semántica de la expresión o, peor aún, se olvida de break
y no se puede producir un error (a pesar de lo que dice @Recurse) sin utilizar el final
:
String name;
switch(pluginType) {
case CANDIDATE_EXPORT:
name = "Candidate Stuff";
//break; whoops forgot break..
//this will cause a compile error for final ;P @Recurse
case JOB_POSTING_IMPORT:
name = "Blah";
break;
}
// code, code, code
// Below is not possible with final
name = "Whoops bug";
Debido al nombre de la configuración del error (además de olvidar break
otro error), ahora puedo hacer esto accidentalmente:
String name;
switch(pluginType) {
case CANDIDATE_EXPORT:
name = "Candidate Stuff";
break;
//should have handled all the cases for pluginType
}
// code, code, code
// Below is not possible with final
name = "Whoops bug";
La variable final obliga a una evaluación única de qué nombre debería ser. Similar a cómo una función que tiene un valor de retorno siempre debe devolver un valor (ignorando excepciones), el bloque de cambio de nombre tendrá que resolver el nombre y, por lo tanto, vincularlo a ese bloque de conmutadores, lo que facilita la refactorización de fragmentos de código (es decir, Eclipe refactor: método de extracción) .
Lo anterior en OCaml:
type plugin = CandidateExport | JobPostingImport
let p = CandidateExport
let name = match p with
| CandidateExport -> "Candidate Stuff"
| JobPostingImport -> "Blah" ;;
El match ... with ...
evalúa como una función, es decir, expresión. Observe cómo se ve nuestra declaración de cambio.
Aquí hay un ejemplo en Scheme (Racket or Chicken):
(define name
(match b
[''CandidateExport "Candidate Stuff"]
[''JobPostingImport "Blah"]))