2010-02-09 12 views
18

Eclipse tiene una opción para advertir sobre la asignación de los parámetros de un método (dentro del método), como en:¿Es problemático asignar un nuevo valor a un parámetro de método?

public void doFoo(int a){ 
    if (a<0){ 
     a=0; // this will generate a warning 
    } 
    // do stuff 
} 

Normalmente intento activar (y atención) advertencias del compilador casi todos disponibles, pero en este caso me No estoy seguro de si vale la pena.

Veo casos legítimos para cambiar un parámetro en un método (por ejemplo: Permitir que un parámetro sea "desarmado" (por ejemplo, nulo) y sustituyendo automáticamente un valor predeterminado), pero pocas situaciones donde podría causar problemas, excepto que podría ser un poco confuso reasignar un parámetro en el medio del método.

¿Utiliza tales advertencias? ¿Por qué por qué no?

Nota:

evitar esta advertencia es, por supuesto, equivalente a lo que el parámetro del método final (sólo entonces se trata de un error de compilación :-)). Entonces esta pregunta Why should I use the keyword "final" on a method parameter in Java? podría estar relacionada.

+1

En este caso, sugiero lanzar una excepción en lugar de ocultar el error. –

+0

posible duplicado de [¿Por qué debería usar la palabra clave "final" en un parámetro de método en Java?] (Http://stackoverflow.com/questions/500508/why-should-i-use-the-keyword-final-on -a-method-parameter-in-java) – nawfal

+0

http://stackoverflow.com/questions/3972510/the-parameter-foo-should-not-be-assigned-whats-the-harm –

Respuesta

9

Para mí, siempre y cuando lo hagas temprano y con claridad, está bien. Como dices, hacerlo enterrado profundamente en cuatro condicionales a la mitad de una función de 30 líneas es menos que ideal.

Obviamente también debe tener cuidado al hacer esto con referencias a objetos, ya que los métodos de llamada en el objeto que se le asignaron pueden cambiar su estado y comunicar la información a la persona que llama, pero por supuesto si ha subido a su marcador de posición, esa información no se comunica.

La otra cara es que declarar una nueva variable y asignarle el argumento (o un argumento predeterminado si el valor predeterminado es) puede ser más claro, y seguramente no será menos eficiente: cualquier compilador decente (ya sea el primario compilador o un JIT) lo optimizarán cuando sea posible.

+0

No está claro para mí cómo la reasignación de una referencia a un objeto hará que el objeto (al que ya no se le haga referencia) le devuelva la información a la persona que llama. ¿Podrías explicarme eso? –

+1

@OscarMk: Mi punto era exactamente eso: no lo hará. :-) Así que (digamos) recibe el argumento 'obj', y cerca de la parte superior de la función le asigna una nueva referencia si existe una cierta condición. Cerca de la parte inferior de la función se llama 'obj.foo()'.Si ha asignado una nueva referencia a 'obj', entonces obviamente el objeto de la persona que llama no recibirá la llamada' foo', su reemplazo lo hará, pero no es obvio que al ver el código al final, eso ocurrirá. –

+0

J Crowder: Sí, eso es lo que pensé, gracias. –

1

Las diferentes advertencias del compilador pueden ser apropiadas para diferentes situaciones. Claro, algunos son aplicables a la mayoría o a todas las situaciones, pero este no parece ser uno de ellos.

Me gustaría pensar en esta advertencia en particular ya que el compilador le da la opción de ser advertido sobre la reasignación de un parámetro de método cuando lo necesite, en lugar de una regla de que los parámetros del método no deberían reasignarse. Su ejemplo constituye un caso perfectamente válido para ello.

12

La parte confusa es el motivo de la advertencia. Si reasigna un parámetro a un nuevo valor en el método (probablemente condicional), entonces no está claro, qué es a. Es por eso que se ve como un buen estilo, para dejar los parámetros del método sin cambios.

+0

Estoy de acuerdo en que es bastante confuso. En general, si está pasando un param, debe usar ese param, no reasignarlo a otra cosa. –

+4

No estoy de acuerdo - las entradas a menudo necesitan ser desinfectadas. – danben

+8

Sanitizar en una nueva variable local. – Mnementh

8

La asignación de un parámetro de método no es algo que la mayoría de las personas esperan que ocurra en la mayoría de los métodos. Como leemos el código asumiendo que los valores de los parámetros son fijos, una asignación generalmente se considera una práctica deficiente, aunque solo sea por convención y por el principle of least astonishment.

Siempre hay alternativas a la asignación de parámetros de método: por lo general, una copia temporal local está bien. Pero en general, si encuentra que necesita controlar la lógica de su función mediante la reasignación de parámetros, podría beneficiarse de la refactorización en métodos más pequeños.

+1

* "Asignar un parámetro de método no es algo que la mayoría de la gente espera que suceda ..." * Lo disputaré como una afirmación universal. De hecho, diría que en lenguajes * funcionales * y similares (incluido JavaScript), está condenado cerca de la norma. En mi experiencia, es menos común en Java y C++, y ni común ni poco común en C. Por qué debería ser así, no sé, pero puede tener algo que ver con los enfoques que las personas toman para resolver problemas en diferentes idiomas y entornos. . –

+1

Nitpicking: en un lenguaje ** funcional **, la asignación no ocurre, solo nuevas vinculaciones, al igual que los lenguajes imperativos declaran una nueva variable temporal. En realidad, sugeriría que lo que describa es ** uno ** de los motivos por los cuales JavaScript tiene una mala reputación, aunque su diseño como un prototipo basado en lenguaje OO es bastante ingenioso. Una vez se dijo del Amiga que era mucho mejor que sus fanboys ... –

+1

La pregunta está etiquetada como Java, no como Javascript o como un lenguaje funcional. Para los lenguajes imperativos habituales es como está escrito aquí. – Mnementh

0

a veces lo uso en situaciones como éstas:

void countdown(int n) 
{ 
    for (; n > 0; n--) { 
     // do something 
    } 
} 

para evitar la introducción de una variable i en el bucle. Normalmente, solo uso este tipo de 'trucos' en funciones muy breves.

Personalmente, me disgusta mucho 'corregir' los parámetros dentro de una función de esta manera. Prefiero atraparlos mediante aseveraciones y asegurarme de que el contrato sea el correcto.

+4

Lo siento, pero creo que su ejemplo es el caso perfecto * para * esta advertencia. Lo encuentro innecesariamente complicado. Por ejemplo, ¿qué sucede si la función crece más tarde (como siempre ocurre con las funciones) e intenta usar n para, por ejemplo, imprimir "Iteración de "? – sleske

0

Por lo general, no es necesario asignar nuevos valores a los parámetros del método.

En cuanto a las mejores prácticas - la advertencia también evita la confusión cuando se enfrentan a un código como:

 public void foo() { 
      int a = 1; 
      bar(a); 
      System.out.println(a); 
     } 

     public void bar(int a) { 
      a++; 
     } 
7

Reasignación a la variable de parámetro del método suele ser un error si el parámetro es un tipo de referencia.

Considere el siguiente código:

MyObject myObject = new myObject(); 
myObject.Foo = "foo"; 
doFoo(myObject); 

// what's the value of myObject.Foo here? 

public void doFoo(MyObject myFoo){ 
    myFoo = new MyObject("Bar"); 
} 

Mucha gente va a esperar que en después de la llamada a doFoo, myObject.Foo será igual a "bar". Por supuesto, no lo hará - porque Java no es pase por referencia, pero pase por el valor de referencia - es decir, se pasa una copia de la referencia al método. La reasignación a esa copia solo tiene un efecto en el ámbito local, y no en el sitio de llamada. Este es uno de los conceptos más comúnmente incomprendidos.

+2

En realidad, los métodos Java son solo call-by-value. Sin embargo, no creo que esto tenga mucho que ver con la pregunta. – danben

+0

@dan Creo que es relevante. * ¿Es problemático asignar un nuevo valor a un parámetro de método? "- Sí, puede ser, porque puede no hacer lo que alguien espera. –

+3

Correcto, pero en este caso particular, se refiere a alguien que no entiende cómo el lenguaje funciona. Las advertencias del compilador no van a proteger contra eso. – danben

0

Usted debe escribir el código sin ningún efecto secundario: cada método debe ser una función que no cambia. De lo contrario, es un comando y puede ser peligroso.

Ver definiciones para command y function en el sitio web de DDD:

Función: Una operación que calcula y devuelve un resultado sin efectos secundarios observables.

Comando: Una operación que produce algún cambio en el sistema (para el ejemplo , estableciendo una variable). Una operación que crea intencionalmente un efecto secundario .

+3

@ Jean-Philippe: (No considero la modificación de la buena práctica del parámetro del método) La pregunta no es sobre los efectos colaterales. Cambiar realmente un parámetro primitivo en Java exactamente -efecto visto que Java es "paso por valor". Usted está introduciendo el concepto de transparencia referencial y funciones puras, que pueden ser entretenidas en el mundo de la programación funcional. Pero aquí estamos hablando de Java y encontrará que en Java a * lot * del método de Java en realidad no son referencialmente transparentes. La pregunta original no es sobre "establecer una variable", se trata de modificar un parámetro de método. – SyntaxT3rr0r

Cuestiones relacionadas