¡Hola Mundo!

Las funciones son un concepto fundacional en la programación. Tan importantes son que vale la pena que sean lo primero que aprendamos.

Una función toma unos parámetros o input y produce un valor de retorno o output. Los pasos que se siguen para esa transformación reciben el nombre de algoritmo.

Ejemplos sencillos de una función son:

  • Un procedimiento que calcule el precio que el consumidor debe pagar, teniendo como input el precio base y el valor del impuesto a cobrar, y como output el precio final.
  • Un procedimiento que devuelva sinónimos de una palabra, teniendo como input la palabra que nos interesa, y como output una lista de palabras.
  • Un procedimiento que indique si un año es bisiesto, teniendo como input el número del año y como output un predicado verdadero si es bisiesto o falso en caso contrario.
  • Una función que resuelva una sopa de letras, teniendo como input una cuadrícula cuadrada con letras mayúsculas y una lista de palabras a buscar, y como output una sopa de letras donde las palabras de la lista aparezcan destacadas.

Los algoritmos son secuenciales, llevamos a cabo un primer paso antes de llevar a cabo un segundo paso, etc. hasta que finalmente somos capaces de devolver el output esperado.

Veamos una función muy sencilla:

Código 1 - ¡Hola Mundo!
String saludos() {
  return "¡Hola Mundo!";
}
Input
> saludos();
Output
¡Hola Mundo!

¡Has escrito tu primera función! Felicitaciones.

El Código 1 muestra una función en Java que retorna una cadena de caracteres, llamadas String, en este caso "Hola Mundo".

La línea 01 tiene 3 aspectos importantes de todas las funciones, en orden:

  1. Valor de retorno u output, en nuestro ejemplo String. El valor de retorno es importante para saber qué vamos a obtener después de llamar a nuestra función.
  2. El identificador de la función, en nuestro caso saludos. El identificador es importante para poder distinguir las diferentes funciones que tengamos.
  3. Y los parámetros o input, que siempre están entre paréntesis, «(" y ")». En este caso no hay parámetros, nuestra función siempre va a retornar el mismo valor.

Estos 3 elementos se llaman la firma de una función.

Al final de la línea 01 encontramos una llave de apertura «{» y en la línea 03 encontramos una llave de cierre «}», ellas forman un bloque. Los bloques nos ayudan a agrupar las instrucciones de nuestra función y de esta forma reconocer rápidamente una instrucción a qué función pertenece.

La línea 02 tiene una sentencia fácilmente identificable por el punto y coma, «;», al final. En este caso es una sentencia return, indicada por la palabra clave return usada en ella, que nos indica cuál es el output de la función. T oda función debe terminar en una sentencia return implícita o explícita. Luego viene un String, indicado por comillas dobles ", que rodean la cadena de caracteres "¡Hola Mundo!".

Leyendo el código podemos ver que al llamar la función saludos() obtendremos la cadena de caracteres "¡Hola Mundo!"

Esta es una de las funciones más simples que podemos hacer, con el pasar de los capítulos iremos aprendiendo cómo hacer funciones más complejas.

Revisemos cada concepto en más detalle.

Valor de Retorno
El valor de retorno del código 01 es String, que representa una cadena de caracteres. Sin embargo las funciones pueden retornar otros tipos de datos, como números, fechas o incluso tipos de datos que nosotros mismos definamos.
Identificadores
El identificador del código 01 es «saludos». El uso de un buen identificador es muy importante para nuestra capacidad de entender el código que nosotros escribimos o que escriben otras personas. Sin embargo no todos los identificadores son válidos, hay unas reglas básicas. Aquí las más importantes:
Identificador ¿Válido? Explicación
mi saludo maravilloso ❌ Los identificadores no pueden tener espacios.
101saludos ❌ Los identificadores pueden tener números, pero no pueden empezar con ellos.
SopaDeLetras ✅ Los identificadores pueden llevar mayúsculas y minúsculas.
CONSTANTE_GRAVITACIONAL ✅ Los identificadores pueden usar "_", por ejemplo para separar palabras en mayúsculas.
Parámetros
Los parámetros siempre van después del identificador de una función y van entre paréntesis. Si no hay nada entre los paréntesis es porque la función no tiene parámetros. Las funciones sin parámetros suelen ser poco comunes, pero a veces son útiles. Pronto veremos funciones con parámetros.
Bloques
En el código 01, vemos un bloque delimitado por las llaves, la de apertura en la línea 01 y la de cierre en la línea 03. Un bloque siempre es una manera de agrupar elementos de nuestro código. Si tenemos muchas líneas de código es importante poder entender rápidamente a dónde pertenecen. Por ejemplo la línea 02 sabemos que pertenece a la función saludos porque está definida dentro del bloque de esa función. Además de funciones, hay otros elementos que usan bloques y en todos cumplen la misma función: agrupar.
Sentencias
Finalmente en la línea 02 hay una sentencia. Una sentencia indica una instrucción que se le da al computador. Una sentencia siempre termina en «;».
Bloques
En el código 01, vemos un bloque delimitado por las llaves, la de apertura en la línea 01 y la de cierre en la línea 03. Un bloque siempre es una manera de agrupar elementos de nuestro código. Si tenemos muchas líneas de código es importante poder entender rápidamente a dónde pertenecen. Por ejemplo la línea 02 sabemos que pertenece a la función saludos porque está definida dentro del bloque de esa función. Además de funciones, hay otros elementos que usan bloques y en todos cumplen la misma función: agrupar.

Todas las funciones deben terminar en una sentencia return, es decir una sentencia que inicia con la palabra clave return. Una sentencia return indica el valor que se va a retornar una vez que la función termina de ser ejecutada. En la función «saludos»; siempre retornamos la misma cadena de caracteres: "¡Hola Mundo!"

Pronto escribiremos funciones más complejas. Las funciones pueden tener múltiples sentencias, cada una haciendo un paso intermedio para calcular el valor final. Lo más importante a tener en cuenta es que una función se ejecuta una línea a la vez, en el orden que aparecen.

¡Hola Mundo! ¡Hola Java!

Código 2 - saludos() con parámetros
String saludosPara(String quien) {
  return String.format("¡Hola %s!", quien);
}
Input
> saludosPara("Mundo");
> saludosPara("Java")
Output
¡Hola Mundo!
¡Hola Java!

La función saludosPara() es muy similar a la función saludos() pero ahora tiene un parámetro. Un parámetro agrega flexibilidad a una función, dado que una función sin parámetros retornaría siempre el mismo valor. ¿Qué sucede si queremos saludar, no solo al mundo, sino a otras personas o cosas? ¡Parámetros al rescate!

En la línea 01 se define un parámetro dentro de los paréntesis. Un parámetro tiene 2 partes: un tipo de dato, como lo tienen los valores de retorno, y un identificador. Para el Código 02 el parámetro también es un String y decidimos usar el identificador "quien" para ayudar a recordar el papel que tiene dentro de la función. Podríamos haber usado cualquier identificador y la función seguiría retornando el valor esperado, pero usar un buen identificador hace que nuestro código sea más legible.

Una función puede tener varios parámetros, separados por comas, y de cualquier tipo. Por ahora solo usaremos Strings porque son fáciles de usar y de hecho son bastante importantes en la programación.

La línea 02 usa la función String.format(), ¿de dónde salió? Resulta que todos los lenguajes de programación incluyen una librería estándar con funciones generales. De esta manera sin haber escrito una línea de código, ya tienes la capacidad de hacer muchas cosas.

String.format() permite crear una cadena de caracteres combinando diferentes partes. La función necesita al menos 2 parámetros: un formato y un valor que suele venir de una variable, en nuestro caso un parametro. En este caso tenemos un formato de saludo y tenemos a quien queremos saludar. El formato necesita un marcador de posición para saber cómo formar el String resultante, en String.format() este es "%s". La función va a tomar los argumentos y va a ir reemplazando los marcadores de posición con ellos.

Podemos pensar la ejecución de saludosPara() en 3 reemplazos:

  1. saludosPara("Mundo")
  2. String.format("¡Hola %s!")
  3. "¡Hola Mundo!"

Si utilizamos diferentes argumentos, "Java" en vez de "Mundo", obtendremos diferentes saludos.

¡Genial! Ya podemos crear saludos a todo lo que se nos ocurra.

¡Hola Mundo! version 2.0

Código 3 - ¡Hola Mundo! 2.0
String saludosPara(String quien) {
  return String.format("¡Hola %s!", quien);
}

String saludos() {
  return saludosPara("Mundo");
}
Input
> saludos();
> saludosPara("Mundo")
Output
¡Hola Mundo!
¡Hola Mundo!

Cuando escribimos la función saludosPara() ¿no se te hizo algo familiar? De alguna manera podemos ver como saludos() y saludosPara() tienen alguna similitud. De hecho si lo piensas bien, ¡saludos() es una versión específica de saludosPara()! Es una versión de saludosPara() que siempre saluda al Mundo.

Esta relación la podemos poner de manifiesto en el código, y lo que podemos hacer es invocar a la función saludosPara() dentro de saludos(). Esto es una manera de reutilización de código que es una muy buena práctica y una muy importante en programación, de hecho antes hemos visto que tiene un lema “No reinventar la rueda”. Y de una manera anexa, también es una manera de reducir la repetición en nuestro código que es igualmente una muy importante práctica.

Con el Código 03, si más adelante queremos cambiar el formato del saludo, entonces solo tendremos un lugar donde hacer el cambio, pero ambas funciones verán el cambio.

El Código 03 también nos reitera que dentro de una función podemos usar funciones dentro de funciones incluso las que hemos definido nosotros. No solo es permitido sino que es algo que debemos fomentar. En un sentido, la programación trata de hacer pequeñas partes y después usar esas pequeñas para crear partes más complejas.

Es muy importante que empieces a ejercitar el hábito de escribir pequeñas funciones y utilizarlas como partes de otra función. Lo inverso es también importante, si vas a crear una función, piensa cómo puedes dividir el algoritmo en partes más pequeñas y escribir una función para cada una.

Espacio en blanco

Código 4 - saludosPara() con mucho espacio en blanco
String saludosPara
(String quien) 
{
      return String.format("¡Hola %s!", quien);
}
Código 5 - saludosPara() con no mucho espacio en blanco
String saludosPara(String quien){return String.format("¡Hola %s!", quien);}

El espacio en blanco es cualquier caracter que parezca un espacio, esto incluye espacios, tabulaciones y saltos en línea. El espacio en blanco no tiene ninguna afectación en el funcionamiento de una función, es netamente una opción para mejorar la legibilidad para los seres humanos. Cuánto espacio en blanco es el exacto para mejorar la legibilidad de un código es una cuestión subjetiva, pero parece claro que el Código 04 tiene mucho y el Código 05 tiene muy poco. Por lo tanto, busca escribir código con una cantidad de espacio en blanco que esté entre esos dos estilos, pero sobre todo no temas agregar un poco de espacio en blanco para darle espacio a respirar a los elementos que componen una sentencia para hacerlos más fáciles de entender.

Comentarios

Código 6 - Comentarios
String saludosPara(String quien) {
  return String.format("¡Hola Mundo!" ,quien);
}

String saludos() {
  return saludosPara("Mundo!"); // evitar repetición
}

La línea 06 tiene un comentario de una sola línea, empieza con “//” y termina en el siguiente salto de línea. Los comentarios son ignorados por el compilador, son realmente para dejar notas para las personas que puedan leer el código.

Dejar notas en tu código puede ayudar a que sea más fácil de entender. Pero ten cuidado de que el comentario no se desactualice si cambias el código.

Funciones

Quiz Interactivo


Antes de intentar los ejercicios, toma unos minutos para verificar tu entendimiento de Funciones tomando este quiz.

  • Las preguntas y el orden de las opciones son diferentes cada vez que tomes el quiz.
  • Las preguntas que tengas mal, vuelven a aparecer luego hasta que las contestes correctamente.
  • Cada pregunta tiene una pista y una explicación.

Ejercicios

Errores del compilador y ejecución

Escribe los siguientes códigos, lee el error que te devuelve el compilador o el ambiente de ejecución. Después escribe el código correcto de modo que al ejecutarlo ya no salgan errores.

E1.1
err() {
  return "¿Dónde está el error?";
}
E1.2
string err2() {
  return "¿String o string?";
}
E1.3
String err3(quien) {
  return String.format("%s, ¿cuál es el error?¿String o string?", quien);
}
E1.4
String err4() {
  return "Este es un error sutil"
}
E1.5
String err5() {
  "Este es un poco menos sutil";
}
E1.6
String err6 {
  return "¡Hola Error!";
}
E1.7
String err7(String quien) {
  return format("%s ¿Un poco mañoso, no?", quien);
}

Ejercicios de Codificación

E1.8: Llena los huecos para crear una función que dados 3 Strings que sean emojis, los devuelva en formato "[%s, %s, %s]" por ejemplo al invocar la función así: adivinaLaPelicula("❄","🛳","💑"), retornaría "[❄, 🛳, 💑]". Para cada hueco con una letra, escoge el reemplazo utilizando una de las opciones numeradas. Una vez que utilices una opción numerada ya no la puedes usar en otro reemplazo.

String _A_(String emoji1_B_ String emoji2_C_ String emoji3) _D_
  return _E_("[%s, %s, %s]"_F_ emoji1_G_ emogi2_H_ emoji3);
_I_
  1. ,
  2. ,
  3. ,
  4. ,
  5. ,
  6. }
  7. {
  8. adivinaLaPelicula
  9. String.format

E1.9: Llena los huecos, para crear una función que concatene la cadena "こんにちは" (hola en japonés) y un parámetro dado. Para cada hueco con una letra, escoge el reemplazo utilizando una de las opciones numeradas. Una vez que utilices una opción numerada ya no la puedes usar en otro reemplazo.

_A_ _B_ {
  _C_ String.format("こんにちは_D_", _E_)_F_
}
  1. return
  2. ;
  3. dare
  4. konnichiwa(String dare)
  5. %s
  6. String

E1.10: Escribe una función separador() que retorne el String "<<<>>>"

Input
> separador()
Output
"<<<>>>"

E1.11: Escribe una función vocales() que retorne el String "aeiou"

Input
> vocales()
Output
"aeiou"

E1.12: Escribe una función títuloAdornado() que tome un String como parámetro y retorne el mismo String precedido por "<<< " y antecedido por " >>>"

Input
> títuloAdornado("Java")
> títuloAdornado(">>> <<<")
> títuloAdornado("A + B")
Output
"<<< Java >>>""
"<<< >>> <<< >>>"
"<<< A + B >>>"

Ejercicios de Corrección de Código

Para estos problemas, mira los ejemplos de uso de una función y luego revisa el código inicial que no está funcionando como se espera. Ejecútalo y luego corrígelo para coincidir con los ejemplos.

E1.13: Escribe una función títuloAdornado() que tome un String como parámetro y retorne el mismo String precedido por "<<< " y antecedido por " >>>"

Input
> adornado("Java")
> adornado("Mundo")
Output
"<=Java=>"
"<=Mundo=>"
String adornado(String frase) {
    return String.format("<=%s=>, frase");
}

E1.14

Input
> concatenar("Hola","Mundo")
> concatenar("A", "Z")
Output
"[Hola+Mundo]"
"[A+Z]"
String concatenar(String s1, String s2) {
    return String.format("[%s+%s]", s2, s1);
}

© 2022 Carlos Obregón. This work is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0)

Scroll to Top