Programación en Java/Parámetros de una Función
Los parametros de una función son los valores que esta recibe por parte del código que la llama. Pueden ser tipos simples u objetos.
En la declaración de la función se escriben después del nombre entre paréntesis indicándose el tipo de cada uno y su nombre. Veamos esto a modo de ejemplo:
int dividir(int dividendo, int divisor) { ... }
Está función recibe dos parámetros, ambos de tipo entero, uno el divisor y otro el dividendo.
A la hora de llamar a la función, los parametros se escriben también a continuación del nombre entre parentesis; pero en este caso no se indica el tipo de estos. Veamoslo en un ejemplo:
int resultado = dividir(8,4);
En esta linea, se asigna a la variable entera resultado el retorno de la función dividir pasandole como parametros 8 y 4. dividir será una función de la clase a la cual pertenece nuestro objeto. Si queremos llamar a una función pública de un objeto externo utilizaríamos un código similar a:
MyClaseMatematica objInstancia = new MyClaseMatematica(); int resultado = objInstancia.dividir(8,4);
Es importante recordar que en java, los parametros de los tipos primitivos (int, long, etc.) SIEMPRE se pasan por valor. Los objetos y arrays se pasan por referencia.
Si no queremos que la función devuelva ningún parámetro debemos utilizar el tipo void. P.ej:
void print(String mensajeAImprimir) { .... }
Funciones estáticas
editarSupongamos que tenemos una clase de funciones matemáticas llamada Calculadora. La misma puede contener métodos para el cálculo de logarítmos, cosenos, etc... Es un poco molesto tener que instanciar un objeto de dicha clase para poder utilizar la misma tal y como se muestra en el siguiente ejemplo:
Calculadora objetoCalculadora = new Calculadora(); float resultado = objetoCalculadora.logaritmo(33.4);
Para solucionar esto podemos crear funciones estáticas. Estas funciones pueden ser invocadas utilizando directamente la clase, no un objeto instancia de la misma. Para ello basta añadir el atributo static a la función. En el caso anterior:
class Calculadora { ... float logaritmo(float entrada){ float resultado; ... return resultado; } }
Entonces el ejemplo anterior se simplifica y queda simplemente como:
float resultado = Calculadora.logaritmo(33.4);
No se debe abusar de las funciones estáticas ya que entonces perdemos la orientación a objetos de Java. Debe ser el sentido común quien nos indique cuando realmente merece la pena utilizar las mismas. Un ejemplo donde suele ser conveniente crear funciones estáticas es en las "fábricas" de objetos. Las fábricas de objetos crean y retornan un nuevo objeto de forma similar al constructor de una clase, pero teniendo en cuenta el contexto de la aplicación. Las fábricas de objetos al tener información sobre el contexto/estado de la aplicación pueden realizar tareas que un constructor no es capaz. P.ej, la conexión por red suele estar asociada a un objeto. Las creación de una nueva conexión por red es un proceso lento (en comparación a la velocidad de proceso de una CPU moderna) y es mejor reutilizar conexiones de red creadas anteriormente antes de crear una nueva. En tal caso creamos una fábrica de conexiones con una función estática getNuevaConexion:
class FabricaDeConexiones { static java.util.ArrayList listaDeConexiones = new java.util.ArrayList();
static void Conexion getNuevaConexion(){ for (int indice=0; indice<listaDeConexiones.size(); indice++){ if listaDeConexiones.get(indice).estaLibre = true { return listaDeConexiones.get(indice); } } Conexion nuevaConexion = new Conexion(....); listaDeConexiones.add(nuevaConexion); } }
En el ejemplo anterior FabricaDeConexiones.getNuevaConexion() consulta un listado de conexiones. Antes de crear una nueva conexión recorre el listado de conexiones ya existentes y si hay alguna conexión libre devuelve la misma antes de crear una nueva.
Así en vez de utilizar el código:
Conexion miConexion = new Conexion();
lo reemplazamos con:
Conexion miConexion = FabricaDeConexiones.getNuevaConexion();
que será mucho más rápido y fiable.
Buenas prácticas
editar- En algunos lenguajes sin soporte para excepciones es común utilizar un entero como valor de retorno para indicar si hubo o no error. En general 0 significa que no paso nada y un valor distinto de cero indica un error. En Java (y cualquier otro lenguaje con control de excepciones) es una mala práctica utilizar un entero para devolver un error. Es mejor generar y lanzar un objeto excepción para indicar un error en la función. Es fácil olvidar comprobar el valor retornado de una función, especialmente si la función invocada pertenece a una librería y va a ser utilizada por terceros que pueden NO ser conscientes de que la función devuelve error. Entonces el error quedaría oculto y se manifestaría aleatóreamente en otra parte del código haciendo muy difícil su depuración y mantenimiento.
En vez de escribir:
int imprimeTodo(String nombre, String apellido1, String apellido2){ if (nombre ==null || nombre =="") return 1; if (apellido1==null || apellido1=="") return 2; if (apellido2==null || apellido2=="") return 3; System.out.println(nombre+" "+apellido1+" "+apellido2); return 0; }
escribiremos:
void imprimeTodo(String nombre, String apellido1, String apellido2){ String errores=""; if (nombre ==null || nombre =="") errores += "nombre no puede ser nulo/vacio,"; if (apellido1==null || apellido1=="") errores += "apellido1 no puede ser nulo/vacio,"; if (apellido2==null || apellido2=="") errores += "apellido2 no puede ser nulo/vacio,"; if (errores!="") throw new Excepcion(errores); System.out.println(nombre+" "+apellido1+" "+apellido2); }
- El valor de los parámetros enviados a la función deben comprobarse antes de ejecutar la lógica de la función. Si los mismos no son válidos debe lanzarse una excepción e interrumpir la ejecución de la misma. Esto ayuda a detectar errores y hace el código más comprensible y fácil de leer.