Métodos y descomposición de programas en Java
return. Descubre dónde puede utilizarse cada variable, por qué un método trabaja con copias de sus argumentos y cómo la pila de llamadas lleva el seguimiento de los métodos en ejecución. Sobrecarga métodos y predice a qué versión llama Java. Por último, divide un problema en métodos pequeños que hagan una sola cosa, elimina el código repetido y construye y prueba un programa método por método.PrincipianteUnidad 3 de 11 del curso Curso de Programación orientada a objetos con Java
Lo que aprenderás
- Define métodos estáticos, llámalos desde
mainy entre sí, y proporciónales la información que necesitan mediante parámetros.- Define un método y llámaloEscribe la cabecera y el cuerpo de un método en el lugar adecuado, llama al método por su nombre y sigue cómo la ejecución salta al método y regresa.
- Pasa información a un método mediante parámetrosDeclara parámetros con un tipo y un nombre, llama al método con argumentos compatibles y utiliza varios parámetros en el orden adecuado.
- Define un método y llámalo
- Escribe métodos que calculen un valor y lo devuelvan con
return, y utiliza los valores devueltos en variables, expresiones y condiciones.- Devuelve un valor y utilízaloDeclara un tipo de retorno, devuelve un resultado con una sentencia return y decide en el código que llama qué hacer con el valor devuelto.
- Realiza retornos desde el interior de condicionales y buclesUtiliza sentencias return dentro de sentencias if y bucles, asegúrate de que cada ruta devuelva un valor y escribe métodos que respondan a una pregunta de sí o no.
- Devuelve un valor y utilízalo
- Identifica dónde puede utilizarse cada variable, qué puede y qué no puede cambiar un método en el código que lo llama y cómo la pila de llamadas lleva el seguimiento de los métodos en ejecución.
- Identifica dónde puedes utilizar cada variableAplica las reglas de ámbito a las variables locales, los parámetros y las variables declaradas en bloques, y corrige los errores de compilación causados por errores de ámbito.
- Comprende que los argumentos se pasan como copiasPredice qué puede cambiar un método en el código que lo llama: el método trabaja con copias de los valores de los argumentos, por lo que reasignar un parámetro no cambia la variable de quien llama.
- Sigue las llamadas a métodos en la pila de llamadasSigue cómo Java registra los métodos en ejecución en marcos de pila, sigue programas en los que unos métodos llaman a otros e interpreta una traza de la pila.
- Identifica dónde puedes utilizar cada variable
- Da el mismo nombre a varios métodos con distintas listas de parámetros y predice a qué versión llama Java para un conjunto dado de argumentos.
- Escribe métodos sobrecargadosDeclara métodos que comparten un nombre, identifica qué diferencias hacen que una sobrecarga sea válida y utiliza la sobrecarga cuando los métodos realizan la misma tarea.
- Predice qué método sobrecargado se ejecutaDetermina qué versión elige Java según los tipos de los argumentos, incluida la ampliación automática, y reconoce las llamadas que no compilan.
- Escribe métodos sobrecargados
- Divide un problema en métodos pequeños que hagan una sola cosa, sustituye el código repetido por métodos con parámetros y construye y prueba un programa método por método.
- Asigna una tarea clara a cada métodoReconoce un programa bien dividido, separa el código que hace demasiado y mantén el cálculo separado de la entrada y la salida.
- Sustituye código repetido por un método con parámetrosEncuentra código que se repite con pequeñas diferencias, conviértelo en un método cuyos parámetros recojan esas diferencias y comprueba que el programa siga comportándose igual.
- Diseña un programa de forma descendente y pruébalo método por métodoPlanifica un programa como una secuencia de llamadas a métodos, escríbelo paso a paso con métodos provisionales y prueba cada método con datos de entrada cuyos resultados conozcas.
- Asigna una tarea clara a cada método
Guía de estudio de Métodos en Java
1Escribe y llama a tus propios métodos
Un programa es más fácil de seguir cuando sus pasos significativos tienen nombres. Un método da un nombre a un grupo de sentencias y una llamada ejecuta esas sentencias en el punto donde se necesitan. Empieza con un método que siempre imprima la misma línea y después añade parámetros para que una sola definición pueda manejar distintas entradas. Leer una cabecera y relacionarla con una llamada te permite ver qué información necesita cada paso antes de examinar su cuerpo.
1.1 Define un método y llámalo
Un método es un bloque de sentencias con nombre que realiza una tarea. Definir un método hace que esa tarea esté disponible; llamarlo hace que se ejecute.
Lee la cabecera y el cuerpo
public static void printLine() {
System.out.println("----------");
}
La primera línea es la cabecera. Lee sus partes de izquierda a derecha:
publicpermite que el código de otras clases llame al método.statichace que el método pertenezca a la clase. No se necesita un objeto para llamarlo.voidindica que el método no devuelve ningún valor.printLineda nombre a la tarea.()es la lista vacía de parámetros: este método no necesita datos de entrada.
Las llaves encierran el cuerpo, las sentencias que se ejecutan al hacer una llamada. No hay punto y coma entre esta cabecera y su llave de apertura.
Coloca la definición en la clase
public class Main {
public static void main(String[] args) {
System.out.println("Start");
printLine();
System.out.println("Middle");
printLine();
}
public static void printLine() {
System.out.println("----------");
}
}
main y printLine son métodos independientes dentro de Main. La llave de cierre de main aparece antes de la definición de printLine. No se puede definir un método dentro de otro; una llave mal colocada puede producir «illegal start of expression».
Las definiciones pueden aparecer en cualquier orden. Mover printLine encima de main no cambia cuándo se ejecuta. Un método al que nunca se llama no se ejecuta solo porque su definición aparezca en el archivo.
Sigue una llamada y el regreso a quien llama
La llamada printLine(); consta del nombre, los paréntesis y un punto y coma, porque la llamada es una sentencia independiente. La ejecución comienza en main:
- Imprime «Start».
- Entra en
printLine, imprime diez guiones y después continúa tras la llamada. - Imprime «Middle».
- Entra de nuevo en
printLinee imprime otra vez diez guiones.
La salida es:
Start
----------
Middle
----------
Ambas llamadas utilizan la misma definición. Cambiar la línea que imprime cambia los dos lugares donde se utiliza.
Nombra y llama a los métodos con precisión
Utiliza un verbo o una frase verbal en camelCase, empezando con minúscula: printReceipt, calculateAverage o isValidCode. Java distingue mayúsculas y minúsculas: PrintLine() no puede encontrar un método llamado printLine. Escribir printLine; también falla; los paréntesis forman parte de la llamada.
Para un método estático de otra clase, escribe primero el nombre de la clase. Math.max(3, 8) da 8, Math.abs(-4) da 4 y Math.sqrt(16.0) da 4.0. A tus propios métodos de la misma clase puedes llamarlos solo por su nombre.
Estos ejemplos utilizan la forma clásica basada en clases con public static void main(String[] args). Java 25 también admite archivos fuente compactos con void main() y sin una clase que los rodee. Mantén la forma clásica al ejecutar estos ejemplos; sus métodos auxiliares se declaran static. Los métodos de la biblioteca de Java a los que llamas, como System.out.println, no tienen por qué ser estáticos.
Puntos clave
- Coloca las definiciones de métodos dentro de la clase y fuera de otros métodos.
- Una definición hace que una tarea esté disponible; una llamada la ejecuta y después continúa en quien llamó.
- Escribe paréntesis en una llamada y un punto y coma cuando la llamada sea una sentencia.
- Utiliza un nombre descriptivo en camelCase y respeta exactamente sus mayúsculas y minúsculas.
- Llama a un método estático de otra clase con el nombre de esa clase, como en
Math.max(3, 8).
1.2 Pasa información a un método mediante parámetros
Un parámetro permite que un método maneje valores que cambian de una llamada a otra. Un argumento es el valor que se proporciona para ese parámetro cuando se llama al método.
Da un tipo y un nombre a cada dato de entrada
public static void printStars(int count) {
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println();
}
int count declara un parámetro. En printStars(3);, el argumento 3 se convierte en el valor inicial de count. El bucle se ejecuta tres veces, por lo que imprime ***, y después println() termina la línea. printStars(8); utiliza el mismo cuerpo con count igual a 8.
El tipo se escribe en la definición, no en la llamada. Escribe printStars(5);, no printStars(int 5);.
Evalúa los argumentos antes de entrar en el cuerpo
Un argumento puede ser un literal, una variable o una expresión:
int n = 4;
printStars(n * 2);
Java evalúa primero n * 2. Pasa el valor resultante 8, por lo que el cuerpo comienza con count igual a 8. El nombre de la variable de quien llama no tiene que coincidir con el nombre del parámetro.
Relaciona varios parámetros por posición
Cada parámetro necesita su propio tipo. Un método para rectángulos puede comenzar con esta cabecera:
public static void printRectangle(int width, int height)
La llamada printRectangle(5, 2); da a width el valor 5 y a height el valor 2. Invertir los argumentos da un rectángulo de 2 de ancho y 5 de alto. Ambas llamadas compilan porque los dos argumentos son int; solo la figura que se pretende obtener permite saber qué orden es correcto. Escribir (int width, height) en la cabecera falla porque height no tiene un tipo declarado.
Los tipos diferentes facilitan la detección de algunos errores de orden:
public static void printRepeated(String text, int times) {
for (int i = 0; i < times; i++) {
System.out.print(text);
}
System.out.println();
}
printRepeated("ab", 3); imprime «ababab». printRepeated(3, "ab"); no puede corresponderse con un String seguido de un int. El número de argumentos también debe coincidir: printRectangle(5); deja un parámetro sin valor.
Comprueba los tipos numéricos compatibles
Java amplía automáticamente un int a double. Un método con los parámetros (double km, double hours) acepta los argumentos (150, 2), lo que le proporciona 150.0 y 2.0. Todo valor int puede representarse exactamente como double.
Java no reduce implícitamente un argumento double para ajustarlo a un parámetro int. printStars(2.9); falla porque convertirlo haría perder la parte fraccionaria. La conversión explícita de tipo en printStars((int) 2.9); produce 2, por lo que se imprimen dos estrellas. Utiliza una conversión explícita solo cuando quieras descartar esa parte.
Elige un parámetro para cada dato que necesite la tarea. Recibir texto y una cantidad permite utilizar printRepeated con datos del teclado, una llamada de prueba fija u otro método. Su cuerpo no tiene que decidir de dónde proceden esos valores.
Puntos clave
- Un parámetro se declara en una cabecera; un argumento proporciona su valor en una llamada.
- Java evalúa las expresiones de los argumentos antes de ejecutar el método llamado.
- Los argumentos se corresponden con los parámetros por posición, cantidad y tipo compatible.
- Escribe un tipo para cada parámetro, pero ningún tipo en la llamada.
- Un int puede ampliarse a double; un double necesita una conversión explícita de tipo para convertirse en int.
- Intercambiar argumentos del mismo tipo puede compilar y, aun así, cambiar el resultado.
2Devuelve resultados desde métodos
Un método puede hacer más que imprimir: puede devolver un valor al código que lo llamó. Esto permite utilizar un cálculo en otro cálculo, una condición o un informe posterior. Sigue cómo encajan los tipos de retorno, las expresiones y las asignaciones y después utiliza retornos dentro de decisiones y búsquedas. La posición de un return importa: determina tanto qué respuesta recibe quien llama como qué parte del método llega a ejecutarse.
2.1 Devuelve un valor y utilízalo
Un valor de retorno es un resultado que un método envía a quien lo llamó. Una vez terminada la llamada, esta puede utilizarse como una expresión del tipo de ese resultado.
Declara qué se devuelve
public static int sum(int a, int b) {
return a + b;
}
int sustituye a void en la cabecera porque este método devuelve un entero. La sentencia return evalúa a + b y envía el valor al lugar de la llamada. Para sum(4, 7), ese valor es 11.
Quien llama decide qué sucede después:
int total = sum(4, 7);
System.out.println(sum(4, 7));
int doubled = sum(2, 3) * 2;
La primera línea almacena 11; la segunda imprime 11; la tercera almacena 10. Un valor devuelto también puede utilizarse en una condición, como if (sum(a, b) > 10).
Un resultado int compatible puede ampliarse al devolverse desde un método double. Un resultado double no puede devolverse desde un método int sin una conversión explícita adecuada.
Calcula la expresión antes de convertir el resultado
public static double average(int a, int b) {
return (a + b) / 2.0;
}
Para average(3, 4), el numerador es 7. Dividir por el literal double 2.0 da 3.5. Si la expresión fuera (a + b) / 2, Java primero dividiría dos int y obtendría 3. Solo después ampliaría ese valor al 3.0 devuelto. Un tipo de retorno double no corrige una división entera ya realizada dentro del cuerpo.
Distingue entre devolver e imprimir
| Comportamiento del método | Qué recibe quien llama | Qué aparece en pantalla |
|---|---|---|
return a + b; en un método int | La suma | Nada de esta sentencia |
System.out.println(a + b); en un método void | Ningún valor | La suma |
Una llamada void no puede proporcionar un valor en una asignación ni en otra llamada. Si printSum es void, int total = printSum(1, 2); falla aunque printSum imprima un número. Utiliza un método que devuelva un valor para los cálculos y deja que quien llama decida si lo imprime.
Devuelve texto y respuestas de sí o no
Los tipos de retorno también incluyen String y boolean. Un método de saludo puede devolver "Hello, " + name + "!", lo que da «Hello, Ana!» para el argumento "Ana". Un método isEven(int n) puede devolver n % 2 == 0.
Un método de formato convierte un número en texto reutilizable:
public static String formatDuration(int minutes) {
return minutes / 60 + " h " + minutes % 60 + " min";
}
Para 135, la división entera da 2 horas completas y el resto da 15 minutos. El resultado es «2 h 15 min»; para 60, es «1 h 0 min».
Conserva o combina el resultado
Una llamada como sum(4, 7); compila, pero descarta su resultado. Si square(x) devuelve un valor nuevo, utiliza x = square(x); para almacenarlo en x.
Un resultado también puede convertirse inmediatamente en argumento. En Math.max(sum(1, 2), 4), sum(1, 2) da primero 3 y después Math.max(3, 4) da 4. Evalúa la llamada interna antes de utilizar su resultado en la externa.
Puntos clave
- El tipo de retorno declarado indica a quien llama qué clase de resultado proporciona la llamada.
- Devolver proporciona un valor; imprimir muestra un valor.
- La expresión se calcula antes de convertir su resultado al tipo de retorno.
- Almacena un valor devuelto cuando el código posterior lo necesite; una llamada independiente lo descarta.
- Un valor devuelto puede ser un argumento de otro método.
2.2 Realiza retornos desde el interior de condicionales y bucles
Una sentencia return termina inmediatamente la llamada al método actual. Dentro de un condicional o un bucle, sigue saliendo de todo el método, no solo de ese bloque.
Da una respuesta a cada ruta
public static int larger(int a, int b) {
if (a > b) {
return a;
}
return b;
}
larger(9, 4) devuelve 9 desde dentro del if. Para larger(2, 6), se omite el cuerpo del if y el return final da 6. Entradas iguales como (5, 5) también llegan al return final, que da 5. No se necesita un else después del primer return porque esa ruta ya ha salido del método.
En un método ordinario que devuelve un valor, ninguna ruta posible puede llegar a la llave de cierre sin proporcionar un valor. Un método de signo que devuelve valores solo para entradas positivas y negativas deja el cero sin respuesta:
public static String sign(int n) {
if (n > 0) {
return "positive";
} else if (n < 0) {
return "negative";
}
return "zero";
}
El return final completa el método. Dos sentencias if separadas, una que comprueba n > 0 y otra que comprueba n <= 0, siguen necesitando un return final o una estructura if/else clara. La comprobación de retornos de Java no deduce que esas dos comparaciones cubren todos los enteros. Una sentencia situada directamente después de un return incondicional en el mismo bloque es inalcanzable y se rechaza.
Termina una búsqueda en el momento adecuado
public static int firstMultipleOf7(int start, int end) {
for (int i = start; i <= end; i++) {
if (i % 7 == 0) {
return i;
}
}
return -1;
}
Para (10, 20), el bucle descarta 10, 11, 12 y 13, y después devuelve 14. La llamada termina sin comprobar del 15 al 20. Para (15, 20), el bucle termina sin coincidencias, por lo que el return posterior devuelve -1, la señal acordada de «no encontrado».
Poner else { return -1; } dentro del bucle haría que terminara después del primer candidato que no cumple la condición. La búsqueda desde 10 indicaría entonces un fallo antes de llegar a 14. El retorno que indica el fallo debe ir después de haber probado todos los candidatos.
Devuelve la propia condición
Una comparación ya produce un booleano. Escribe return n % 2 == 0; en lugar de un if/else que devuelva true y false por separado. El nombre de un método booleano suele empezar con is o has, de modo que una llamada se lee de forma natural dentro de un if.
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0;
}
Esto devuelve true para 2024 y 2000, pero false para 1900 y 2023. Utiliza directamente if (isLeapYear(y)).
Sal anticipadamente de un método void
Un método void utiliza return; sin valor. Por ejemplo, printSquareRoot(double x) puede imprimir «No real square root» y retornar inmediatamente para una entrada negativa. Para otras entradas puede imprimir Math.sqrt(x), que da 1.5 para 2.25. Escribir return 5; en un método void falla porque su cabecera indica que no devuelve ningún valor.
Puntos clave
returntermina inmediatamente la llamada actual, incluso cuando está dentro de un bucle.- Un método que devuelve un valor no debe llegar a su llave de cierre sin una respuesta.
- Coloca el return que indica el fallo de una búsqueda después del bucle, para poder comprobar los candidatos posteriores.
- Una comparación puede devolverse directamente como booleano.
- Utiliza
return;sin valor para salir anticipadamente de un método void. - El código situado directamente después de un return incondicional en el mismo bloque es inalcanzable.
3Sigue las variables y las llamadas a lo largo de un programa
Una llamada a un método no da a un método auxiliar acceso a todas las variables del programa. Cada llamada tiene sus propios parámetros y variables locales, y Java guarda esos valores en un marco de pila independiente. Utiliza el ámbito para decidir dónde se puede usar un nombre, el paso por valor para predecir qué pueden cambiar las asignaciones y la pila de llamadas para seguir el trabajo pendiente. Estas tres ideas explican por qué dos variables pueden tener el mismo nombre y contener valores distintos.
3.1 Identifica dónde puedes utilizar cada variable
El ámbito de una variable es la región del código donde puede utilizarse su nombre. Empieza por las llaves que rodean su declaración: un nombre local pertenece a un método o bloque concreto.
Las variables locales de quien llama permanecen allí
public static void main(String[] args) {
int price = 20;
printDouble(price);
}
public static void printDouble(int price) {
System.out.println(price * 2);
}
El price de main y el parámetro price de printDouble son variables independientes. El argumento proporciona el valor que necesita el método auxiliar, por lo que este imprime 40.
Eliminar el parámetro y llamar a printDouble() no permite que el método auxiliar lea la variable local price de main. Su cuerpo fallaría con «cannot find symbol». Llamar a un método desde otro no une sus ámbitos. Distintos métodos pueden utilizar cada uno el nombre count sin vincular sus variables.
Un bloque anidado crea un ámbito más pequeño
Una variable local puede utilizarse desde su declaración hasta la llave de cierre de su bloque. Un parámetro está disponible en todo el cuerpo de su método. Un contador declarado en for (int i = 0; i < 3; i++) pertenece a ese bucle; i no puede leerse después.
Para conservar un resultado después de un bucle, decláralo antes del bucle:
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
System.out.println(sum);
Las sumas hacen que sum pase por 1, 3, 6, 10 y 15. La impresión final puede leer sum porque el bloque que lo contiene no ha terminado. i solo se necesita para el bucle y permanece dentro de su ámbito.
Mover int sum = 0; al cuerpo del bucle crea un nuevo sum en cada pasada. Cada uno empieza en cero y desaparece al final de esa pasada. No puede mantener una suma acumulada ni imprimirse después del bucle.
Comprueba por separado los nombres y los valores iniciales
Dos variables locales con el mismo nombre no pueden tener ámbitos que se solapen dentro de un método. Un método con un parámetro x no puede declarar otra variable local x; un bucle que declara i no puede declarar otra i en su cuerpo. Cambia el nombre de la segunda variable o utiliza la existente.
Dos bucles consecutivos pueden declarar cada uno int i. El ámbito del primer bucle ha terminado antes de la segunda declaración. Las llaves, no el archivo completo, determinan esa reutilización.
Un nombre válido también necesita un valor antes de leerse. int total; total++; falla porque ++ debe leer el valor anterior y una variable local no recibe automáticamente un valor inicial. Utiliza int total = 0; para una suma acumulada.
Mantén una variable local en el bloque más pequeño que la necesite. Si un método necesita información de quien lo llama, convierte esa información en un parámetro. Si quien llama necesita un resultado, devuélvelo. Así, la cabecera y el cuerpo del método muestran de dónde proceden sus datos.
Puntos clave
- Un nombre local está disponible desde su declaración hasta el final de su bloque.
- Un método llamado no puede leer por nombre las variables locales de quien lo llamó.
- Declara un acumulador antes de un bucle cuando deba conservar un total o leerse después.
- Los ámbitos de nombres locales iguales no pueden solaparse dentro de un método, y las variables locales necesitan valores antes de utilizarse.
3.2 Comprende que los argumentos se pasan como copias
Java pasa los argumentos por valor. Al comienzo de una llamada, cada parámetro recibe una copia del valor de su argumento. Asignar un valor al parámetro cambia esa variable local.
Sigue la copia por separado
public static void main(String[] args) {
int score = 10;
addBonus(score);
System.out.println(score);
}
public static void addBonus(int score) {
score = score + 5;
System.out.println(score);
}
Hay dos variables llamadas score. Sigue sus valores en cada momento:
| Momento | score de main | score de addBonus |
|---|---|---|
| Antes de la llamada | 10 | Aún no hay llamada |
Al entrar en addBonus | 10 | 10 |
| Después de la asignación del método auxiliar | 10 | 15 |
| Después de que retorne el método auxiliar | 10 | La llamada ha terminado |
El método auxiliar imprime 15 y después main imprime 10. Compartir un nombre no hace que las dos variables compartan almacenamiento. Cambiar el nombre del parámetro no alteraría este comportamiento.
Devuelve el nuevo valor y almacénalo
public static int addBonus(int score) {
return score + 5;
}
Con esta versión, escribe score = addBonus(score);. Java copia el valor anterior en el parámetro, calcula 15, lo devuelve y lo asigna a la variable de quien llama. La asignación en quien llama es el paso que cambia esa variable.
Un resultado también puede almacenarse en otro lugar. Si triple(int n) multiplica su n local por 3 y lo devuelve, entonces int a = 4; int b = triple(a); deja a igual a 4 y da a b el valor 12. Imprimir a + " " + b muestra «4 12».
Aplica la misma regla a las referencias String
Una variable String contiene una referencia a un objeto String. Java copia esa referencia en un parámetro String:
public static void exclaim(String text) {
text = text + "!";
}
Si word de quien llama se refiere a «hi», exclaim(word); deja word haciendo referencia a «hi». La concatenación crea un nuevo String y la asignación solo cambia aquello a lo que se refiere el parámetro. El contenido existente de las cadenas String no puede modificarse.
Para conservar el nuevo texto, devuelve text + "!" desde un método String como exclaimed y después escribe word = exclaimed(word);.
En el caso de objetos mutables, como las listas, una referencia copiada puede seguir apuntando al mismo objeto. Un método puede cambiar el contenido de ese objeto mediante la referencia copiada. Reasignar el parámetro sigue sin poder hacer que la variable de quien llama se refiera a otro objeto. Tanto la regla de la referencia copiada como la del número copiado son paso por valor.
Puedes reasignar un parámetro, pero una variable local independiente como result puede facilitar la lectura de un cálculo largo: mantiene disponible la entrada original y muestra qué valor se devolverá.
Puntos clave
- Cada parámetro recibe una copia del valor de su argumento.
- Reasignar un parámetro deja sin cambios la variable de quien llama.
- Para conservar un nuevo valor calculado, devuélvelo y asígnalo en quien llama.
- Una referencia copiada puede acceder al mismo objeto mutable, pero la reasignación del parámetro sigue siendo local.
3.3 Sigue las llamadas a métodos en la pila de llamadas
La pila de llamadas registra las llamadas que han comenzado pero aún no han terminado. Cada llamada recibe un marco de pila con sus parámetros, variables locales y el lugar donde continuará quien la llamó.
Añade un marco, termínalo y retíralo
La pila funciona según el principio último en entrar, primero en salir. La llamada más reciente está arriba y se ejecuta mientras quien la llamó espera debajo. Cuando retorna, Java retira su marco y reanuda la ejecución de quien llamó.
public static void main(String[] args) {
int total = totalSeconds(2, 30);
System.out.println(total);
}
public static int totalSeconds(int minutes, int seconds) {
int fromMinutes = toSeconds(minutes);
return fromMinutes + seconds;
}
public static int toSeconds(int minutes) {
return minutes * 60;
}
Sigue el trabajo pendiente:
maincomienza y llama atotalSeconds(2, 30). Su asignación atotaldebe esperar.- El nuevo marco tiene
minutes = 2yseconds = 30. Llama atoSeconds(minutes)y espera el valor defromMinutes. toSecondsrecibe su propiominutes = 2. Devuelve120y se retira su marco.totalSecondsalmacenafromMinutes = 120, suma30y devuelve150. Se retira su marco.mainalmacenatotal = 150e imprime150.
En el punto de mayor profundidad, los marcos de abajo arriba son main, totalSeconds y toSeconds. Ambos métodos auxiliares tienen un parámetro llamado minutes, pero esos parámetros ocupan marcos distintos. Las variables locales de quien llama y está esperando no se vuelven visibles para el método situado encima.
Una llamada posterior recibe un marco nuevo. Un contador local no recuerda su valor anterior después de que su llamada haya terminado; el valor de retorno es lo que puede llevar un resultado de vuelta.
Lee una traza de la pila desde el error hacia fuera
Una excepción no manejada imprime una traza de la pila que muestra dónde ocurrió el error y qué llamadas llevaron hasta allí. Este es un archivo completo:
public class Main {
public static void main(String[] args) {
report(300, 0);
}
public static void report(int meters, int minutes) {
int speed = perMinute(meters, minutes);
System.out.println(speed + " m per minute");
}
public static int perMinute(int meters, int minutes) {
return meters / minutes;
}
}
La primera línea de salida es Exception in thread "main" java.lang.ArithmeticException: / by zero. Los marcos que aparecen debajo son:
at Main.perMinute(Main.java:12)
at Main.report(Main.java:7)
at Main.main(Main.java:3)
El marco superior identifica la división entera por cero. Los dos siguientes localizan las llamadas que llevaron hasta ella. Los números de línea corresponden a esta disposición exacta del archivo; añadir una línea los cambia.
La pila tiene un espacio limitado. Una cadena que sigue añadiendo llamadas sin dejar que terminen puede provocar StackOverflowError. La vista de pila de un depurador te permite examinar la misma cadena mientras está pausada en un punto de interrupción, incluidas las variables independientes de cada llamada en espera.
Puntos clave
- Cada llamada añade un marco nuevo; un retorno retira ese marco y reanuda la ejecución de quien llamó.
- La llamada sin terminar más reciente se ejecuta primero: la pila funciona según el principio último en entrar, primero en salir.
- Las variables locales con el mismo nombre en distintos marcos son variables independientes.
- Sigue un valor devuelto hasta la expresión o asignación que espera su resultado.
- Lee una traza de la pila desde el marco del error, arriba, hacia quienes lo llamaron, debajo.
- Una cadena que sigue añadiendo marcos puede agotar la pila.
4Sobrecarga métodos
Una operación útil puede aceptar varios tipos de entrada. La sobrecarga permite que esas formas compartan un nombre y mantengan una lista de parámetros distinta para cada una. Primero comprueba si dos declaraciones tienen realmente firmas diferentes. Después sigue la elección del compilador en una llamada: cuenta los argumentos, identifica sus tipos y compara las versiones compatibles. El tipo de la variable que recibe el resultado no puede resolver una llamada cuyos argumentos no identifican una sobrecarga adecuada.
4.1 Escribe métodos sobrecargados
La sobrecarga da a los métodos el mismo nombre con distintas listas de parámetros. Es útil cuando los métodos realizan la misma tarea para distintas cantidades o tipos de datos de entrada.
Compara las firmas
Para estos métodos, una firma consta del nombre y los tipos de parámetros en orden. El número de parámetros se desprende de esa lista.
public static int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
public static int max(int a, int b, int c) {
return max(max(a, b), c);
}
public static double max(double a, double b) {
if (a > b) {
return a;
}
return b;
}
Las firmas son max(int, int), max(int, int, int) y max(double, double). max(3, 9) devuelve 9 utilizando la primera. max(3, 9, 5) llama a la segunda: la llamada interna con dos int devuelve 9, después la llamada externa con dos int compara 9 y 5 y también devuelve 9. max(2.5, 1.0) utiliza la versión double y devuelve 2.5.
Identifica qué cambios no cuentan
Cambiar solo un tipo de retorno no crea una sobrecarga. Estas cabeceras entran en conflicto:
public static int area(int w, int h)
public static double area(int w, int h)
Ambas tienen la firma area(int, int). Java rechaza la declaración duplicada. Cambiar los nombres de los parámetros a width y height también deja la misma firma: quienes llaman proporcionan valores por posición, no por nombre de parámetro.
El orden de los distintos tipos sí cuenta. describe(String s, int n) y describe(int n, String s) son firmas distintas. Compilan juntas, pero quien llama tiene que recordar un orden que es fácil confundir, así que utiliza un par así solo cuando ayude al diseño.
Deja que una sobrecarga más corta proporcione un valor predeterminado
Java no proporciona valores predeterminados para los parámetros en las declaraciones de métodos. Una sobrecarga más corta puede llamar a otra más larga con un argumento fijo:
public static void printLine(int length, char symbol) {
for (int i = 0; i < length; i++) {
System.out.print(symbol);
}
System.out.println();
}
public static void printLine(int length) {
printLine(length, '-');
}
printLine(5, '*'); imprime *****. printLine(4); entra en el método más corto, que llama al más largo con 4 y '-', e imprime ----. El bucle está en un solo lugar, por lo que los cambios en la tarea de impresión se aplican a ambas formas.
La biblioteca de Java también utiliza sobrecargas. System.out.println acepta un int, un double, un char, un boolean o un String mediante distintas versiones. Math.abs y Math.max ofrecen versiones para int, long, float y double.
Mantén un solo significado para el nombre compartido. Imprimir un recibo e imprimir una etiqueta son tareas distintas; nombres claros como printReceipt y printLabel indican a quien llama qué tarea se realizará.
Puntos clave
- Los métodos sobrecargados comparten un nombre y difieren en el número, los tipos o el orden de los tipos de parámetros.
- Los tipos de retorno y los nombres de los parámetros no distinguen las firmas.
- Una sobrecarga más corta puede llamar a otra más larga con un argumento predeterminado fijo.
- Utiliza un mismo nombre sobrecargado para una tarea con distintas formas de entrada.
4.2 Predice qué método sobrecargado se ejecuta
El compilador elige una sobrecarga según el número y los tipos de los argumentos. Determina esa elección antes de considerar cómo se utilizará el valor devuelto.
Empieza por las coincidencias exactas
Supón que una clase define show(int x) y show(double x). show(5) utiliza la versión int porque el literal 5 es un int. show(5.0) utiliza la versión double. Un valor entero escrito como 5.0 sigue siendo una expresión double.
Para una llamada con varios argumentos, compara el tipo en cada posición. Una candidata con un número incorrecto de argumentos no puede ser compatible.
Permite la ampliación cuando sea necesaria
Si solo existe show(double x), show(5) es válido: el int se amplía a 5.0. Las rutas de ampliación de tipos primitivos incluyen:
byte → short → int → long → float → double
char → int → long → float → double
Si existen tanto show(long x) como show(double x), un argumento int selecciona long. Ese es el tipo de parámetro compatible más específico: un long puede ampliarse a double, mientras que un double no puede ampliarse de vuelta a long.
La ampliación es una conversión numérica permitida; no garantiza que cada conversión de este tipo conserve todos los dígitos. En particular, convertir un long suficientemente grande a double puede redondear su valor. La conversión de int a double utilizada en los ejemplos anteriores conserva exactamente todos los valores int.
Un char también tiene un valor numérico. Con letter(int code) y letter(String text), letter('A') llama a la versión int con 65. Un carácter no se convierte en String para ajustarse a un parámetro. Las comillas dobles en "A" crearían, en cambio, un argumento String.
Rechaza la reducción implícita
Si solo existe show(int x), show(5.0) falla. Java no reduce un argumento double solo porque su valor sea un número entero. show((int) 5.0) pasa un int después de una conversión explícita de tipo.
Del mismo modo, las versiones de max para dos y tres int no pueden aceptar max(1). Ninguna candidata tiene el número de parámetros necesario, por lo que el compilador indica «no suitable method found». Compara la lista de candidatas con los argumentos proporcionados.
Separa la selección de la sobrecarga de la conversión del resultado
Considera int twice(int n) y double twice(double x). En double d = twice(3);, el argumento selecciona la sobrecarga int. Esa llamada devuelve 6 y después la asignación lo amplía a 6.0. El destino d no selecciona la sobrecarga double.
Reconoce una llamada ambigua
public static void combine(int a, double b) { }
public static void combine(double a, int b) { }
combine(1, 2) es compatible con la primera tras ampliar su segundo argumento y con la segunda tras ampliar su primero. Ninguna firma es más específica en ambas posiciones. Java indica «reference to combine is ambiguous»; no elige la definición escrita primero.
combine(1, 2.0) solo es compatible con (int, double), porque la otra firma necesitaría una conversión de reducción de 2.0. Un tipo de argumento claro o un conjunto de sobrecargas mejor diseñado elimina la ambigüedad.
Puntos clave
- Elige una sobrecarga según el número y los tipos de argumentos en tiempo de compilación.
- Una coincidencia exacta tiene prioridad; la ampliación puede hacer que otra versión sea compatible.
- Java no reduce implícitamente los argumentos numéricos de los métodos.
- La variable que recibe el resultado no elige la sobrecarga.
- Hay ambigüedad cuando varias versiones son compatibles y ninguna es más específica para toda la llamada.
5Divide un programa en métodos
Los métodos de un programa deben revelar su plan. Asigna a cada método una tarea significativa, pásale los valores que necesita y deja que su resultado alimente el siguiente paso. El código repetido suele revelar que falta un método; un método largo suele revelar varias tareas mezcladas. Planifica primero las cabeceras, construye piezas pequeñas con resultados conocidos y conéctalas gradualmente. Esto facilita ver tanto el flujo de datos como la ubicación de un nuevo error.
5.1 Asigna una tarea clara a cada método
La descomposición consiste en dividir un problema en tareas más pequeñas y resolver cada tarea en su propio método. Elige tareas cuyos nombres ayuden a leer el plan del programa.
Separa el cálculo de la entrada y la salida
Un programa sobre un recorrido en bicicleta necesita calcular la velocidad y mostrar un informe. Ambos utilizan los mismos datos, pero realizan tareas distintas:
public static double kilometersPerHour(double km, double hours) {
return km / hours;
}
public static void printRideReport(double speed) {
System.out.println("Speed: " + speed + " km/h");
}
Para un recorrido de 150 km en 2 horas, el cálculo devuelve 75.0. El método que genera el informe recibe ese valor y lo muestra. Quien llama conecta los pasos:
double speed = kilometersPerHour(150, 2);
printRideReport(speed);
El método de cálculo no lee datos del teclado ni imprime un informe. Otro programa puede utilizarlo para comparar recorridos o almacenar velocidades sin cambiar su cuerpo. Para probarlo, llámalo con datos de entrada conocidos y compara el número devuelto con el esperado.
Reconoce un método con demasiadas tareas
Un nombre como readAndCheckAndPrint sugiere varias acciones. Otras pistas son las secciones marcadas por comentarios, un cuerpo que ocupa más de una pantalla y grupos de variables que sirven para fines no relacionados. Son motivos para examinar el método, no límites mecánicos sobre el número de líneas que puede tener.
Divide el código en un punto que tenga sentido. El código de entrada puede obtener un valor, un método auxiliar booleano puede comprobarlo, un cálculo puede devolver un resultado y un método de informe puede mostrarlo. Así, main se lee como una breve descripción de cómo se conectan esas tareas.
Los métodos centrados en una tarea son más fáciles de leer por separado, reutilizar y probar. Si cambia el formato de un informe, edita el método que lo genera. Si un cálculo es incorrecto, prueba ese cálculo sin necesidad de introducir todos los datos de una sesión.
Deja que la cabecera explique el flujo de datos
En kilometersPerHour(double km, double hours), el nombre indica el resultado, los nombres de los parámetros indican las cantidades y el tipo de retorno double indica la clase de respuesta. Un breve comentario Javadoc puede añadir el significado de los datos de entrada y del resultado:
/**
* Calculates a ride's average speed.
* @param km distance in kilometers
* @param hours elapsed time in hours, greater than zero
* @return speed in kilometers per hour
*/
Coloca ese comentario directamente encima de la cabecera del método. Un comentario útil añade información como las unidades o un requisito de entrada; no necesita narrar cada línea del cuerpo.
Un método auxiliar que solo necesita su propia clase puede ser private static. private impide que otras clases lo llamen, mientras que el código de la misma clase puede seguir utilizándolo. public static pone el método auxiliar a disposición de otras clases.
Dividir cada sentencia evidente en su propio método envoltorio también puede oscurecer el plan. Conserva un método cuando su nombre represente un paso significativo o un cálculo reutilizable. Una cadena de métodos auxiliares que simplemente transmiten la misma llamada añade lugares que examinar sin explicar mejor la tarea.
Puntos clave
- Descompón un programa en tareas significativas con nombres claros.
- Los métodos de cálculo reciben parámetros y devuelven resultados; los métodos de informe los muestran.
- Los métodos auxiliares centrados en una tarea pueden reutilizarse y probarse por separado.
- Una cabecera y un breve comentario Javadoc pueden indicar los datos de entrada, las unidades y el resultado.
- Utiliza
private staticpara los métodos auxiliares a los que solo debe llamar su propia clase. - Divide el código donde un nombre aclare la tarea, no en cada sentencia individual.
5.2 Sustituye código repetido por un método con parámetros
El código duplicado repite la misma tarea en más de un lugar. Cuando solo difieren los valores de entrada, un método con parámetros puede mantener unido el trabajo común.
Encuentra el cálculo común
Supón que un programa suma del 1 al 10 y después del 1 al 50:
int total1 = 0;
for (int i = 1; i <= 10; i++) {
total1 += i;
}
System.out.println("Sum 1 to 10: " + total1);
int total2 = 0;
for (int i = 1; i <= 50; i++) {
total2 += i;
}
System.out.println("Sum 1 to 50: " + total2);
Ambos bucles comienzan en 1, acumulan una suma y se detienen en un límite superior. Solo cambia ese límite. Un parámetro n puede llevarlo a un cálculo compartido.
Extrae el método
public static int sumUpTo(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
n es el dato de entrada que varía. total e i son variables de trabajo que pertenecen al método auxiliar. Quien llama necesita la suma final, por lo que el método auxiliar devuelve un int.
Sustituye las dos secciones repetidas:
System.out.println("Sum 1 to 10: " + sumUpTo(10));
System.out.println("Sum 1 to 50: " + sumUpTo(50));
sumUpTo(10) devuelve 55 y sumUpTo(50) devuelve 1275. Las líneas impresas son «Sum 1 to 10: 55» y «Sum 1 to 50: 1275», como antes. Las descripciones permanecen en quien llama; el bucle solo realiza el cálculo.
Comprueba la extracción en un orden fijo
- Marca las sentencias que realizan la tarea repetida.
- Identifica cada valor que difiere entre las copias.
- Convierte esos valores en parámetros con tipos adecuados y devuelve cualquier resultado que se necesite fuera.
- Sustituye cada copia por una llamada con sus datos de entrada originales.
- Ejecuta los mismos datos de entrada antes y después, y compara el comportamiento.
Cambiar la estructura del código conservando su comportamiento es refactorización. Si dejas una copia original, una corrección posterior seguirá teniendo dos lugares que actualizar. Mover una impresión al interior de un bucle o cambiar un extremo del bucle modifica el comportamiento, aunque el código sea ahora más corto.
Cuando dos diferencias tienen tipos distintos, utiliza parámetros correspondientes. Repetir distintos textos un número diferente de veces sugiere printRepeated(String text, int times); la palabra es un String y la cantidad es un int.
El código que parece similar no siempre hace la misma tarea. Un parámetro booleano que alterna un método entre cálculos no relacionados puede hacer que sus llamadas sean difíciles de interpretar. Da nombres distintos a tareas distintas. Extrae la operación repetida solo cuando variar sus entradas conserve un significado claro.
Puntos clave
- Identifica la tarea común y convierte sus datos de entrada variables en parámetros.
- Mantén locales las variables de trabajo y devuelve cualquier resultado que necesite quien llama.
- Refactoriza todas las copias y compara el comportamiento con los mismos datos de entrada.
- Combina copias de la misma tarea, no tareas no relacionadas que solo parecen similares.
5.3 Diseña un programa de forma descendente y pruébalo método por método
El diseño descendente comienza con la tarea completa y la refina en llamadas a métodos más pequeños. Decide qué necesita y qué devuelve cada llamada antes de completar todos los detalles.
Planifica los pasos y las cabeceras
Un programa semanal de ejercicio lee 7 duraciones diarias, las suma e imprime un informe. Sus métodos auxiliares pueden planificarse así:
readMinutes(Scanner scanner, int day)devuelve los minutos válidos de un día.isValidMinutes(int minutes)responde si la entrada está entre 0 y 1440.formatDuration(int minutes)devuelve texto con las horas completas y los minutos restantes.averagePerDay(int total, int days)devuelve una media double.printSummary(int totalMinutes, int days)imprime el informe.
Se pasa el mismo Scanner a cada llamada de entrada. Un método auxiliar como isValidMinutes no necesita leer datos por sí mismo.
Utiliza métodos provisionales durante la construcción
Un método provisional tiene su cabecera definitiva, pero un cuerpo mínimo temporal, como return 0;. Permite compilar el programa antes de implementar un método auxiliar. Sustituye un método provisional, compila y comprueba ese método antes de sustituir el siguiente. Un método provisional que compila sigue siendo trabajo pendiente; su respuesta fija no puede verificar un cálculo real.
Este es el programa completo:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int total = 0;
for (int day = 1; day <= 7; day++) {
total += readMinutes(scanner, day);
}
printSummary(total, 7);
}
public static int readMinutes(Scanner scanner, int day) {
System.out.println("Minutes for day " + day + ":");
int minutes = scanner.nextInt();
while (!isValidMinutes(minutes)) {
System.out.println("Enter minutes from 0 to 1440:");
minutes = scanner.nextInt();
}
return minutes;
}
public static boolean isValidMinutes(int minutes) {
return minutes >= 0 && minutes <= 1440;
}
public static String formatDuration(int minutes) {
return minutes / 60 + " h " + minutes % 60 + " min";
}
public static double averagePerDay(int total, int days) {
return (double) total / days;
}
public static void printSummary(int totalMinutes, int days) {
System.out.println("Total: " + formatDuration(totalMinutes));
System.out.println("Daily average: "
+ averagePerDay(totalMinutes, days) + " min");
if (totalMinutes >= 150) {
System.out.println("Weekly goal reached");
}
}
}
Para una entrada entera, readMinutes repite la comprobación del rango hasta que el número es válido. Con las entradas diarias 30, 45, 0, 60, 90, 45 y 45, el total es 315. El formato da «5 h 15 min», la media es 45.0 minutos y el programa indica que se alcanza su meta semanal de 150 minutos.
Comprueba los métodos pequeños y sus límites
Llama a cada método de cálculo con resultados conocidos. formatDuration(0) debe dar «0 h 0 min», 59 da «0 h 59 min», 60 da «1 h 0 min» y 135 da «2 h 15 min». Las entradas justo por debajo de 60 y en ese valor comprueban el cambio de minutos a una hora completa.
Para isValidMinutes, prueba -1, 0, 1440 y 1441. Los resultados esperados son false, true, true y false. Imprimir los valores esperados y reales uno al lado del otro hace visible un error. JUnit automatiza este tipo de comprobación.
El desarrollo ascendente comienza escribiendo y probando métodos auxiliares pequeños y después los une en pasos más grandes. Puedes planificar de forma descendente y construir de forma ascendente: establece primero el flujo de datos, demuestra que los cálculos pequeños funcionan y después comprueba el programa conectado.
Puntos clave
- El diseño descendente convierte una tarea completa en llamadas y después refina cada tarea.
- Decide los datos de entrada y el tipo de retorno de cada método auxiliar antes de escribir su cuerpo.
- Un método provisional conserva una cabecera planificada mientras su cuerpo todavía es temporal.
- Prueba resultados conocidos y valores en los límites o alrededor de ellos.
- Construye y comprueba un método cada vez y después prueba el programa conectado.
- El desarrollo ascendente construye métodos auxiliares pequeños antes de combinarlos.
Ejemplos de Métodos en Java
1Crea un método reutilizable para imprimir líneas
11 pasos
- 1IntroducciónConvierte una acción repetida en una llamada
Un informe necesita un separador corto en varios lugares. Dar un nombre de método a esa acción permite que el informe solicite un separador sin repetir las sentencias de impresión. Esa acción con nombre es un método, y una sola definición sirve para cada llamada.
Empieza con un separador fijo. Después deja que quien llama elija su anchura y símbolo con parámetros. Sigue la definición, la llamada y los valores proporcionados como tres partes distintas de la tarea.
- 2ExplicaciónLee la cabecera de un método
public static void printDivider() { System.out.println("===="); }printDivideres el nombre.publicpermite llamadas desde otras clases;staticsignifica que no se necesita un objeto.voidindica que no se devuelve ningún valor y()indica que no se requieren datos de entrada.La sentencia entre las llaves es el cuerpo. No se imprime nada solo porque exista esta definición.
- 3ConsejoColoca el método auxiliar junto a main
En una clase clásica,
mainyprintDividerson métodos independientes dentro de las mismas llaves de la clase. Cierra el cuerpo demainantes de comenzar la cabecera del método auxiliar.Un método auxiliar puede aparecer encima o debajo de
main; su posición no determina cuándo se ejecuta. Una definición colocada dentro demainse rechaza. Comprueba primero las llaves cuando una cabecera de método produzca «illegal start of expression». - 4EjemploSigue la primera llamada
Supón que
maincontiene:System.out.println("Items"); printDivider(); System.out.println("End");La ejecución primero imprime «Items». La llamada entra en
printDivider, que imprime «====». Cuando termina el método auxiliar,maincontinúa en su siguiente sentencia e imprime «End».El cuerpo del método auxiliar se ejecuta entre las dos sentencias de quien llama, exactamente donde aparece la llamada.
- 5DesafíoColoca un segundo separador
mainllama aprintDivider();, imprime"A"y vuelve a llamar aprintDivider();. ¿Qué tres líneas aparecen?---reveal---
Las líneas son «====», «A» y «====». Cada llamada entra en el mismo cuerpo del método auxiliar, imprime una vez y regresa a su propio lugar en
main.Escribir
printDivider;no haría una llamada. Incluso sin argumentos, los paréntesis son obligatorios. - 6ExplicaciónConvierte la anchura en un dato de entrada
Sustituye el cuerpo fijo por un bucle:
public static void printDivider(int length) { for (int i = 0; i < length; i++) { System.out.print("="); } System.out.println(); }lengthes un parámetro declarado en la cabecera. EnprintDivider(6);, el argumento6se convierte en su valor inicial. Seis pasadas del bucle imprimen seis símbolos antes de que termine la línea. - 7EjemploEvalúa una expresión antes de la llamada
int sections = 3; printDivider(sections + 2);Primero, evalúa
sections + 2para obtener5. Después entra en el método auxiliar con su parámetrolength = 5. Su bucle imprime «=====».sectionsylengthno necesitan tener el mismo nombre. Un parámetro recibe el valor evaluado del argumento; quien llama no escribe el tipo en la llamada. - 8EjemploAñade un segundo dato de entrada variable
Para elegir también el símbolo, utiliza:
public static void printDivider(int length, char symbol) { for (int i = 0; i < length; i++) { System.out.print(symbol); } System.out.println(); }La llamada
printDivider(3, '+');pasa3alengthy'+'asymbol, e imprime «+++». Cada parámetro necesita su propio tipo en la cabecera. - 9ConsejoComprueba la cantidad, el orden y el tipo
Una llamada debe proporcionar un valor compatible para cada parámetro. A
printDivider(3);ahora le falta el símbolo, mientras queprintDivider("3", '+');proporciona texto donde se necesita un int.Java puede ampliar un int a double para un parámetro double. No puede reducir implícitamente
3.7para ajustarlo a este parámetro int. La conversión explícita de tipo(int) 3.7proporciona3al descartar la parte fraccionaria. - 10DesafíoPredice el resultado de una llamada con parámetros
Con el método auxiliar de dos parámetros, ¿qué línea imprime esto?
int width = 4; printDivider(width - 1, '#');---reveal---
Imprime «###». La expresión se evalúa como
3, después el primer parámetro recibe esa cantidad y el segundo recibe'#'. El bucle se ejecuta tres veces.La llamada es una sentencia, por lo que termina con punto y coma. Sus expresiones de argumentos contienen valores, no declaraciones de parámetros.
- 11RepasoIdentifica la acción y sus datos de entrada
Una definición da a una tarea una cabecera y un cuerpo; una llamada la ejecuta y después reanuda la ejecución de quien llamó. Mantén las definiciones dentro de la clase y fuera de otros métodos.
Los parámetros describen los datos de entrada necesarios. Las llamadas proporcionan argumentos evaluados en el orden correspondiente, con la cantidad correcta y tipos compatibles.
2Devuelve respuestas y termina búsquedas
13 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDevuelve un resultado a quien llama
- 2ExplicaciónHaz que una llamada represente un valor
- 3Idea claveImprimir no puede proporcionar un valor a una asignación
- 4EjemploConserva la parte fraccionaria
- 5DesafíoUtiliza el resultado en otra expresión
- 6EjemploDevuelve texto con formato
- 7ExplicaciónUn return termina esta llamada
- 8ConsejoComprueba la ruta que no entra en el if
- 9EjemploEscribe una búsqueda con un resultado de fallo
- 10EjemploSigue la búsqueda hasta que termine
- 11DesafíoDetecta un fallo prematuro
- 12DesafíoConecta el resultado de una búsqueda con una condición
- 13RepasoSigue tanto la respuesta como el punto de parada
3Mantén separadas las variables de cada llamada
15 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónIdentifica cada variable por su llamada
- 2ExplicaciónUn método auxiliar ve sus propias variables locales
- 3EjemploMantén un total fuera del bucle
- 4DesafíoDistingue el ámbito de la inicialización
- 5EjemploCopia un número en un parámetro
- 6EjemploAsigna el nuevo valor devuelto
- 7DesafíoPredice una segunda llamada
- 8ConexiónLas referencias copiadas siguen la misma regla
- 9EjemploInicia un cálculo externo
- 10EjemploPausa a quien llama y añade otro marco
- 11EjemploLleva los resultados hacia abajo en la pila
- 12ConsejoInterpreta un error desde el marco superior
- 13DesafíoIdentifica el trabajo pendiente
- 14DesafíoRelaciona las copias con los resultados de la pila
- 15RepasoMantén distintos los nombres, los valores y los marcos
4Elige el método sobrecargado adecuado
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónUna tarea, varias formas de entrada
- 2ExplicaciónIdentifica una firma
- 3Idea claveUn tipo de retorno no puede crear una sobrecarga
- 4EjemploDelega en la versión completa
- 5DesafíoComprueba una tercera declaración propuesta
- 6ExplicaciónElige una coincidencia numérica exacta
- 7EjemploUtiliza la ampliación sin reducción
- 8EjemploSepara la llamada de su asignación
- 9EjemploCompara cada posición de los argumentos
- 10ConsejoUtiliza la lista de candidatas para diagnosticar una llamada
- 11DesafíoElige una versión y después utiliza su resultado
- 12RepasoComprueba las definiciones antes de las llamadas
5Construye un informe pequeño con métodos auxiliares probados
16 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDivide un informe en tareas pequeñas
- 2ExplicaciónNombra la tarea antes de escribir el cuerpo
- 3EjemploHaz que el cálculo sea reutilizable
- 4EjemploAsigna un método propio a la salida
- 5DesafíoReutiliza un cálculo sin un informe
- 6ExplicaciónIdentifica qué cambia en el código repetido
- 7EjemploElige la cabecera del método extraído
- 8EjemploColoca el bucle compartido en un solo lugar
- 9DesafíoConserva la última repetición
- 10ExplicaciónPlanifica el programa de forma descendente
- 11ConsejoUtiliza un método provisional solo durante la construcción
- 12EjemploPasa el mismo lector de entrada
- 13EjemploComprueba el cálculo antes de conectarlo
- 14EjemploComprueba una secuencia de entrada en el programa conectado
- 15DesafíoLocaliza un error de conexión
- 16RepasoConstruye piezas significativas y conéctalas
Ejercicios de Métodos en Java
Set 1: Llamadas, valores y pasos pequeños de un programa10 Preguntas de Práctica
Pregunta 1 de 10
main y necesita un nuevo método printMenu. ¿Dónde debe ir la nueva definición?Mostrar respuestaOcultar respuesta
main no hace que su definición forme parte de main; colocarla allí crearía una definición de método anidada, que Java rechaza.Pregunta 2 de 10
¿Qué línea imprime esta llamada?
public static void showPair(int rows, int columns) {
System.out.println(rows + ":" + columns);
}
int width = 7;
showPair(3, width - 2);
Mostrar respuestaOcultar respuesta
rows = 3. La expresión width - 2 se evalúa antes de la llamada, por lo que el segundo parámetro recibe 5 y la salida es «3:5». El nombre width de quien llama no cambia la correspondencia de los argumentos por posición.Pregunta 3 de 10
¿Qué valor devuelve halfTotal(8, 5)?
public static double halfTotal(int a, int b) {
return (a + b) / 2;
}
Mostrar respuestaOcultar respuesta
13 y dividirlo por el int 2 produce 6. Ese resultado se amplía al double 6.0 que se devuelve. Un tipo de retorno double no hace que la división anterior utilice decimales; se necesitaría un divisor 2.0 para obtener 6.5.Pregunta 4 de 10
¿Por qué este método no compila?
public static String label(int n) {
if (n >= 0) {
return "ready";
}
}
Mostrar respuestaOcultar respuesta
Pregunta 5 de 10
Un bucle debe sumar los enteros del 2 al 4 e imprimir el total después. ¿Qué declaración debe sustituir al comentario?
// declaration here
for (int i = 2; i <= 4; i++) {
total += i;
}
System.out.println(total);
Mostrar respuestaOcultar respuesta
total a 0 antes del bucle para que las tres sumas actualicen la misma variable y esta siga siendo visible para la impresión final. Declarar solo int total; no asigna un valor inicial, por lo que total += i leería una variable local sin inicializar.Pregunta 6 de 10
¿Qué dos números se imprimen, en orden?
public static void lower(int level) {
level -= 3;
System.out.println(level);
}
int level = 14;
lower(level);
System.out.println(level);
Mostrar respuestaOcultar respuesta
level inicializado a 14, reduce esa copia a 11 y la imprime. El level de quien llama sigue siendo 14 y se imprime después. Utilizar el mismo nombre en ambos métodos no hace que la asignación al parámetro actualice la variable de quien llama.Pregunta 7 de 10
public static int scale(int value). ¿Qué cabecera adicional entraría en conflicto con su firma?Mostrar respuestaOcultar respuesta
scale(int). Su tipo de retorno double y el cambio de nombre del parámetro no la distinguen del método existente. Cambiar el tipo del parámetro o añadir un parámetro crearía una firma diferente.Pregunta 8 de 10
show(int n) y show(double n). ¿Qué método se ejecuta para show(12.0)?Mostrar respuestaOcultar respuesta
12.0 tiene tipo double, por lo que la sobrecarga double es una coincidencia exacta. Que su valor sea un número entero no convierte la expresión en int. La sobrecarga int requeriría una conversión de reducción que Java no realiza implícitamente para este argumento.Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Pregunta 10 de 10
Un programa debe aceptar duraciones de tareas de 0 a 90 minutos e indicar su media. Actualmente utiliza estos métodos auxiliares. ¿Qué dos llamadas con datos de entrada pueden revelar ambos defectos independientes?
public static boolean valid(int m) {
return m > 0 && m <= 90;
}
public static double mean(int total, int count) {
return total / count;
}
Mostrar respuestaOcultar respuesta
valid(0) devuelve incorrectamente false aunque el cero está permitido. mean(7, 2) devuelve 3.0 en lugar de 3.5 porque la división entera se realiza antes de la ampliación. Probar valid(90) y esa media detecta solo el defecto de la división, ya que el extremo superior funciona correctamente.Set 2: Sigue métodos auxiliares y corrige los límites entre métodos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
¿Qué secuencia de líneas se imprime?
public static void frame() {
System.out.println("Open");
mark();
System.out.println("Close");
}
public static void mark() {
System.out.println("Mark");
}
main llama a frame(); y después imprime "Done".
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
public static void repeat(int count). ¿Qué valor recibe count en repeat((int) 3.9 + 2);?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
¿Qué valor se asigna a result?
public static int addTwo(int n) {
return n + 2;
}
public static int product(int a, int b) {
return a * b;
}
int result = product(addTwo(4), addTwo(addTwo(1)));
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
El método debe devolver el primer valor par de un rango que incluye sus extremos, o -1 si no existe ninguno. Devuelve incorrectamente -1 para (9, 12). ¿Qué cambio corrige la búsqueda?
public static int firstEven(int start, int end) {
for (int n = start; n <= end; n++) {
if (n % 2 == 0) {
return n;
} else {
return -1;
}
}
return -1;
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
pages de main. ¿Cómo deben llegar los datos al método auxiliar?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
¿Qué valor devuelve outer(4) a main?
public static int outer(int n) {
int saved = n;
int changed = inner(n + 1);
return saved + changed;
}
public static int inner(int n) {
n *= 2;
return n - 1;
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
printBorder(int length, char symbol), con dos argumentos, ya contiene el bucle de impresión. ¿Cómo debe proporcionar printBorder(int length) un '#' predeterminado sin duplicar el bucle?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Estas sobrecargas comparten una clase. ¿Qué valor se almacena en answer?
public static int adjust(int n) { return n + 1; }
public static double adjust(double n) { return n + 0.5; }
double answer = adjust(6);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
8 * 3 y otro con 11 * 4. Ambos resultados se necesitan para comparaciones posteriores. ¿Qué cabecera de método auxiliar es adecuada para extraer este cálculo compartido?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
public static int countItems(int limit) { return 0; } sea un método provisional útil?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Relaciona argumentos, rutas de retorno y diseño10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Una persona escribe esto dentro de una clase. ¿Por qué se rechaza la definición del método auxiliar?
public static void main(String[] args) {
public static void printTitle() {
System.out.println("Schedule");
}
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
El método devuelve el número de grupos completos. ¿Qué devuelve groups(5, 18)?
public static int groups(int groupSize, int items) {
return items / groupSize;
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
Un método auxiliar de calendario está escrito como se muestra. ¿Qué par de resultados devuelven leap(2100) y después leap(2400)?
public static boolean leap(int year) {
return (year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0;
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
¿Qué texto imprime quien llama?
public static void tag(String name) {
name = name + "-checked";
}
String label = "parcel";
tag(label);
System.out.println(label);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Un informe de error comienza con ArithmeticException: / by zero y estos marcos. ¿Dónde ocurrió la división que falló?
at Main.unitCount(Main.java:23)
at Main.printLoad(Main.java:15)
at Main.main(Main.java:5)
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
public static void describe(String name, int count). ¿Qué cabecera añade una sobrecarga válida cambiando el orden de los tipos de parámetros?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
¿Qué línea imprime esta llamada? El carácter 'B' tiene el valor numérico 66.
public static int code(int n) { return n + 1; }
public static String code(String s) { return s + "!"; }
double result = code('B');
System.out.println(result);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
El programa original imprime los totales 20 y 30, en ese orden. Después de la extracción, utiliza este método auxiliar. ¿Cómo deben escribirse las dos llamadas para conservar esos totales?
public static int sumMultiples(int factor, int count) {
int total = 0;
for (int i = 1; i <= count; i++) {
total += factor * i;
}
return total;
}
El primer bucle original sumaba 2, 4, 6 y 8. El segundo sumaba 5, 10 y 15.
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Un programa lee cinco recuentos diarios, los suma e imprime una media. Las cabeceras planificadas de los métodos auxiliares aparecen abajo. ¿Qué conexión en main permite que el paso de generación del informe reciba todos los datos necesarios?
public static int readCount(Scanner scanner, int day)
public static double average(int total, int days)
public static void printReport(int total, int days)
El Scanner ya está creado.
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Diagnostica interacciones completas entre métodos10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
¿Qué par de valores se imprime como a:b?
public static int shift(int n) {
n += 4;
return n;
}
int a = 2;
int b = shift(a);
a = shift(b);
System.out.println(a + ":" + b);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
¿Qué línea se imprime?
public static int next(int n) { return n + 1; }
public static double half(int n) { return n / 2.0; }
int n = 5;
next(n);
double result = half(next(n)) + n;
System.out.println(result);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
¿Qué valor devuelve locate(5)?
public static int locate(int limit) {
int total = 0;
for (int n = 1; n <= limit; n++) {
total += n;
if (total > 8) {
return n;
}
}
return -1;
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
El código debe sumar los pesos e imprimir su suma después del bucle. Actualmente no compila. ¿Qué cambio corrige el problema de ámbito y conserva una suma acumulada?
for (int box = 1; box <= 3; box++) {
int total = 0;
total += box * 2;
}
System.out.println(total);
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
En el punto marcado, ¿cuáles son los valores de las dos variables locales llamadas saved, leyendo primero el marco externo y después el interno?
public static int outer(int n) {
int saved = n + 2;
return inner(saved) + saved;
}
public static int inner(int n) {
int saved = n * 3;
// program pauses here
return saved;
}
main ha llamado a outer(5).
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Los métodos siguientes están declarados en una clase. ¿Qué ocurre en double result = merge(4, 9);?
public static int merge(int a, double b) { return a; }
public static double merge(double a, int b) { return b; }
public static double merge(double a, double b) { return a + b; }
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
"Crate" con elementos numerados del 1 al 2; el segundo imprime "Bag" con elementos numerados del 1 al 4. ¿Qué cuerpo extraído conserva ese formato para printItems(String label, int count)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Un método auxiliar debe devolver una media diaria decimal:
public static double dailyAverage(int total, int days) {
return total / days;
}
¿Por qué comprobar solo (24, 6) no revela su defecto aritmético?
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Acumulador
sum antes de un bucle para que cada iteración añada al total conservado de la pasada anterior.Argumento
printRepeated("go", 4), los argumentos proporcionan el texto y el número de repeticiones.Á
Ámbito
B
Bloque
C
Cabecera de método
public static void greet() describe una acción a la que se puede llamar, sin datos de entrada ni valor devuelto.Cadena String inmutable
"!" y asignar el resultado a un parámetro String deja sin cambios la referencia de quien llama.Caso límite
-1, 0, 1440 y 1441 como entradas separadas.Código duplicado
Coincidencia exacta
show(int) y show(double), show(9) tiene una coincidencia exacta con la versión int.Conversión de ampliación
12 a un parámetro double le proporciona 12.0 sin necesitar una conversión explícita de tipo.Conversión de reducción
9.0 a un parámetro int falla sin una conversión explícita de tipo, aunque el valor no tenga parte fraccionaria.Conversión explícita de tipo
(int) 4.9 proporciona 4 a un parámetro int al descartar la parte fraccionaria.Cuerpo de método
D
Desarrollo ascendente
Desarrollo incremental
Desbordamiento de pila
StackOverflowError.Descomposición
Diseño descendente
main las llamadas de entrada, cálculo y generación de informes antes de completar los cuerpos de sus métodos auxiliares.E
Extracción de método
sumUpTo(int n) deja su propio texto del informe a cargo de quien llama.F
Firma de método
width por w deja area(int, int) sin cambios y no puede crear una nueva sobrecarga.I
Inicialización
int total = 0; antes de un bucle de suma proporciona a la primera adición un total existente que actualizar.J
Javadoc
/** ... */ encima de una declaración, con etiquetas que describen los parámetros y los resultados.@param minutes para explicar un dato de entrada y @return para describir el texto con formato que produce.L
Lista de parámetros
(int width, int height) requiere dos argumentos, que se corresponden primero con width y después con height.Llamada a método
printHeader(); ejecuta el método de impresión del encabezado en ese punto de quien llama.Llamada ambigua
(int, double) y (double, int) hacen que una llamada con dos argumentos int sea ambigua.Llamada anidada
Math.max(sum(2, 6), 5), el resultado 8 se convierte en el primer argumento de Math.max.M
Marco de pila
minutes porque los parámetros ocupan marcos separados.Método
printHeader() puede imprimir el mismo encabezado de informe en varios lugares de un programa.Método auxiliar
Método booleano
true o false, a menudo para responder a una pregunta que quien llama utiliza directamente como condición.isEven(count) puede colocarse directamente dentro de los paréntesis de una sentencia if.Método estático
Math.abs(-6) utiliza el nombre de clase Math y devuelve el valor positivo 6.Método privado
private static permite que su propia clase lo utilice sin ofrecer una llamada externa.Método provisional
return 0; temporal puede ocupar su lugar mientras se implementa y comprueba el cálculo real.Método sobrecargado que delega
P
Parámetro
printRepeated(String text, int times), text y times son los dos parámetros declarados.Paso por valor
Pila de llamadas
main llama a un método auxiliar que llama a otro método auxiliar, puede haber tres marcos en la pila a la vez.R
Refactorización
Referencia
Resolución de sobrecargas
Retorno anticipado
return candidate;, aunque queden más candidatos en el bucle.S
Sentencia inalcanzable
Sentencia return
return minutes * 60; termina el cálculo y proporciona el número de segundos.Sobrecarga
max pueden aceptar dos int y tres int y mantener un solo significado para el nombre.T
Tipo de retorno
void declara que no proporciona ningún valor.double average(int a, int b) promete un resultado double a quien lo llama.Traza de la pila
Ú
Último en entrar, primero en salir
V
Valor centinela
-1 después de una búsqueda puede indicar «no encontrado» cuando -1 no puede ser una coincidencia válida.Valor de retorno
int total = sum(6, 8);, el 14 devuelto se almacena en la variable total de quien llama.Variable local
total local de un método auxiliar es independiente de una variable local de otro método también llamada total.void
printTotal no puede ocupar el lado derecho de una asignación a un int solo porque imprima un número.- 1Primeros programas en Java
- 2Condiciones y bucles en Java
- 3Métodos en Java
- 4Listas, arreglos y cadenas en Java
- 5Clases y objetos en Java
- 6Objetos y referencias en Java
- 7HashMap y colecciones en Java
- 8Herencia, interfaces y polimorfismo en Java
- 9Excepciones y archivos en Java
- 10Paquetes en Java
- 11Genéricos y expresiones lambda en Java
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.