Métodos y descomposición de programas en Java

Aprende a escribir tus propios métodos estáticos en Java y a construir programas con ellos. Define y llama a métodos, pásales información mediante parámetros y obtén resultados con 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

  1. Define métodos estáticos, llámalos desde main y entre sí, y proporciónales la información que necesitan mediante parámetros.
    • Define un método y llámalo
      Escribe 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ámetros
      Declara parámetros con un tipo y un nombre, llama al método con argumentos compatibles y utiliza varios parámetros en el orden adecuado.
  2. 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ízalo
      Declara 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 bucles
      Utiliza 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.
  3. 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 variable
      Aplica 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 copias
      Predice 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 llamadas
      Sigue 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.
  4. 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 sobrecargados
      Declara 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 ejecuta
      Determina 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.
  5. 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étodo
      Reconoce 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ámetros
      Encuentra 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étodo
      Planifica 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.

Guía de estudio de Métodos en Java

5 capítulos

1

Escribe 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:

  • public permite que el código de otras clases llame al método.
  • static hace que el método pertenezca a la clase. No se necesita un objeto para llamarlo.
  • void indica que el método no devuelve ningún valor.
  • printLine da 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:

  1. Imprime «Start».
  2. Entra en printLine, imprime diez guiones y después continúa tras la llamada.
  3. Imprime «Middle».
  4. Entra de nuevo en printLine e 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.
2

Devuelve 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étodoQué recibe quien llamaQué aparece en pantalla
return a + b; en un método intLa sumaNada de esta sentencia
System.out.println(a + b); en un método voidNingún valorLa 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

  • return termina 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.
3

Sigue 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:

Momentoscore de mainscore de addBonus
Antes de la llamada10Aún no hay llamada
Al entrar en addBonus1010
Después de la asignación del método auxiliar1015
Después de que retorne el método auxiliar10La 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:

  1. main comienza y llama a totalSeconds(2, 30). Su asignación a total debe esperar.
  2. El nuevo marco tiene minutes = 2 y seconds = 30. Llama a toSeconds(minutes) y espera el valor de fromMinutes.
  3. toSeconds recibe su propio minutes = 2. Devuelve 120 y se retira su marco.
  4. totalSeconds almacena fromMinutes = 120, suma 30 y devuelve 150. Se retira su marco.
  5. main almacena total = 150 e imprime 150.

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.
4

Sobrecarga 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.
5

Divide 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 static para 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
  1. Marca las sentencias que realizan la tarea repetida.
  2. Identifica cada valor que difiere entre las copias.
  3. Convierte esos valores en parámetros con tipos adecuados y devuelve cualquier resultado que se necesite fuera.
  4. Sustituye cada copia por una llamada con sus datos de entrada originales.
  5. 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

5 Lecciones Interactivas

1

Crea un método reutilizable para imprimir líneas

11 pasos
Define un método auxiliar, sigue sus llamadas y añade parámetros para las entradas variables.
  1. 1
    Introducció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.

  2. 2
    ExplicaciónLee la cabecera de un método
    public static void printDivider() {
        System.out.println("====");
    }
    

    printDivider es el nombre. public permite llamadas desde otras clases; static significa que no se necesita un objeto. void indica 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.

  3. 3
    ConsejoColoca el método auxiliar junto a main

    En una clase clásica, main y printDivider son métodos independientes dentro de las mismas llaves de la clase. Cierra el cuerpo de main antes 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 de main se rechaza. Comprueba primero las llaves cuando una cabecera de método produzca «illegal start of expression».

  4. 4
    EjemploSigue la primera llamada

    Supón que main contiene:

    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, main continú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.

  5. 5
    DesafíoColoca un segundo separador

    main llama a printDivider();, imprime "A" y vuelve a llamar a printDivider();. ¿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.

  6. 6
    Explicació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();
    }
    

    length es un parámetro declarado en la cabecera. En printDivider(6);, el argumento 6 se convierte en su valor inicial. Seis pasadas del bucle imprimen seis símbolos antes de que termine la línea.

  7. 7
    EjemploEvalúa una expresión antes de la llamada
    int sections = 3;
    printDivider(sections + 2);
    

    Primero, evalúa sections + 2 para obtener 5. Después entra en el método auxiliar con su parámetro length = 5. Su bucle imprime «=====».

    sections y length no necesitan tener el mismo nombre. Un parámetro recibe el valor evaluado del argumento; quien llama no escribe el tipo en la llamada.

  8. 8
    EjemploAñ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, '+'); pasa 3 a length y '+' a symbol, e imprime «+++». Cada parámetro necesita su propio tipo en la cabecera.

  9. 9
    ConsejoComprueba 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 que printDivider("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.7 para ajustarlo a este parámetro int. La conversión explícita de tipo (int) 3.7 proporciona 3 al descartar la parte fraccionaria.

  10. 10
    Desafí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.

  11. 11
    RepasoIdentifica 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.

2

Devuelve respuestas y termina búsquedas

13 pasos
Utiliza valores de retorno en quien llama y después sigue los retornos anticipados y las rutas de retorno completas.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónDevuelve un resultado a quien llama
  2. 2
    ExplicaciónHaz que una llamada represente un valor
  3. 3
    Idea claveImprimir no puede proporcionar un valor a una asignación
  4. 4
    EjemploConserva la parte fraccionaria
  5. 5
    DesafíoUtiliza el resultado en otra expresión
  6. 6
    EjemploDevuelve texto con formato
  7. 7
    ExplicaciónUn return termina esta llamada
  8. 8
    ConsejoComprueba la ruta que no entra en el if
  9. 9
    EjemploEscribe una búsqueda con un resultado de fallo
  10. 10
    EjemploSigue la búsqueda hasta que termine
  11. 11
    DesafíoDetecta un fallo prematuro
  12. 12
    DesafíoConecta el resultado de una búsqueda con una condición
  13. 13
    RepasoSigue tanto la respuesta como el punto de parada
3

Mantén separadas las variables de cada llamada

15 pasos
Sigue el ámbito, los valores copiados y los marcos de pila en espera a través de un programa pequeño.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónIdentifica cada variable por su llamada
  2. 2
    ExplicaciónUn método auxiliar ve sus propias variables locales
  3. 3
    EjemploMantén un total fuera del bucle
  4. 4
    DesafíoDistingue el ámbito de la inicialización
  5. 5
    EjemploCopia un número en un parámetro
  6. 6
    EjemploAsigna el nuevo valor devuelto
  7. 7
    DesafíoPredice una segunda llamada
  8. 8
    ConexiónLas referencias copiadas siguen la misma regla
  9. 9
    EjemploInicia un cálculo externo
  10. 10
    EjemploPausa a quien llama y añade otro marco
  11. 11
    EjemploLleva los resultados hacia abajo en la pila
  12. 12
    ConsejoInterpreta un error desde el marco superior
  13. 13
    DesafíoIdentifica el trabajo pendiente
  14. 14
    DesafíoRelaciona las copias con los resultados de la pila
  15. 15
    RepasoMantén distintos los nombres, los valores y los marcos
4

Elige el método sobrecargado adecuado

12 pasos
Compara firmas, reutiliza una sobrecarga más larga y resuelve llamadas a partir de los tipos de los argumentos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónUna tarea, varias formas de entrada
  2. 2
    ExplicaciónIdentifica una firma
  3. 3
    Idea claveUn tipo de retorno no puede crear una sobrecarga
  4. 4
    EjemploDelega en la versión completa
  5. 5
    DesafíoComprueba una tercera declaración propuesta
  6. 6
    ExplicaciónElige una coincidencia numérica exacta
  7. 7
    EjemploUtiliza la ampliación sin reducción
  8. 8
    EjemploSepara la llamada de su asignación
  9. 9
    EjemploCompara cada posición de los argumentos
  10. 10
    ConsejoUtiliza la lista de candidatas para diagnosticar una llamada
  11. 11
    DesafíoElige una versión y después utiliza su resultado
  12. 12
    RepasoComprueba las definiciones antes de las llamadas
5

Construye un informe pequeño con métodos auxiliares probados

16 pasos
Separa tareas, extrae código repetido y planifica un programa completo en torno a métodos probados.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónDivide un informe en tareas pequeñas
  2. 2
    ExplicaciónNombra la tarea antes de escribir el cuerpo
  3. 3
    EjemploHaz que el cálculo sea reutilizable
  4. 4
    EjemploAsigna un método propio a la salida
  5. 5
    DesafíoReutiliza un cálculo sin un informe
  6. 6
    ExplicaciónIdentifica qué cambia en el código repetido
  7. 7
    EjemploElige la cabecera del método extraído
  8. 8
    EjemploColoca el bucle compartido en un solo lugar
  9. 9
    DesafíoConserva la última repetición
  10. 10
    ExplicaciónPlanifica el programa de forma descendente
  11. 11
    ConsejoUtiliza un método provisional solo durante la construcción
  12. 12
    EjemploPasa el mismo lector de entrada
  13. 13
    EjemploComprueba el cálculo antes de conectarlo
  14. 14
    EjemploComprueba una secuencia de entrada en el programa conectado
  15. 15
    DesafíoLocaliza un error de conexión
  16. 16
    RepasoConstruye piezas significativas y conéctalas

Ejercicios de Métodos en Java

40 Preguntas de Práctica en 4 sets

Set 1: Llamadas, valores y pasos pequeños de un programa10 Preguntas de Práctica

Pregunta 1 de 10

Una clase Java clásica tiene un método main y necesita un nuevo método printMenu. ¿Dónde debe ir la nueva definición?
  1. Dentro de main, después de su última sentencia.
  2. Dentro de la clase, fuera de todos los demás métodos.
  3. Fuera de la clase, después de su llave de cierre.
  4. Dentro del método que necesita llamarlo.
Mostrar respuestaOcultar respuesta
Respuesta: B
La definición de un método pertenece al interior de la clase y al exterior de todos los demás métodos. Llamar a un método auxiliar desde 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);
  1. 5:3
  2. 3:7
  3. 7:3
  4. 3:5
Mostrar respuestaOcultar respuesta
Respuesta: D
El primer argumento proporciona 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;
}
  1. 6.0
  2. 6.5
  3. 13.0
  4. 7.0
Mostrar respuestaOcultar respuesta
Respuesta: A
La suma produce el int 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";
    }
}
  1. El valor de retorno debe imprimirse primero.
  2. La comparación no puede aparecer en un método.
  3. Las entradas negativas llegan al final sin un valor.
  4. Los métodos String no pueden retornar dentro de un if.
Mostrar respuestaOcultar respuesta
Respuesta: C
Una entrada negativa omite el cuerpo del if y llega a la llave de cierre sin un resultado String. Un método con este tipo de retorno necesita un return también para esa ruta. Retornar desde dentro de un if es válido; la ausencia de una respuesta fuera de esa rama causa el error.

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);
  1. int total;
  2. int total = 0;
  3. int total = 2;
  4. int total = i;
Mostrar respuestaOcultar respuesta
Respuesta: B
Inicializa 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);
  1. 11, después 14
  2. 11, después 11
  3. 14, después 11
  4. 14, después 14
Mostrar respuestaOcultar respuesta
Respuesta: A
El método auxiliar recibe su propio 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

Una clase ya declara public static int scale(int value). ¿Qué cabecera adicional entraría en conflicto con su firma?
  1. public static int scale(int value, int factor)
  2. public static double scale(double value)
  3. public static long scale(long value)
  4. public static double scale(int amount)
Mostrar respuestaOcultar respuesta
Respuesta: D
La cabecera adicional con un parámetro int sigue teniendo la firma 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

Una clase tiene show(int n) y show(double n). ¿Qué método se ejecuta para show(12.0)?
  1. show(int), con 12
  2. Ambos, con 12.0
  3. show(double), con 12.0
  4. Ninguno; la llamada es ambigua
Mostrar respuestaOcultar respuesta
Respuesta: C
El literal 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

Un programa de rutas necesita calcular una velocidad media y mostrar un informe. ¿Qué división permite reutilizar el cálculo de velocidad en un programa que compara rutas?
  1. Calcular y devolver la velocidad; imprimirla en otro método.
  2. Calcular e imprimir la velocidad; no devolver ningún valor.
  3. Leer e imprimir la velocidad; recalcularla en cada llamada.
  4. Calcular e imprimir la velocidad; devolver el título del informe.
Mostrar respuestaOcultar respuesta
Respuesta: A
Un método que recibe distancia y tiempo y devuelve la velocidad puede servir tanto para un informe como para una comparación. Mantén la presentación en otro método. Un método void de cálculo que solo imprime su respuesta deja al código de comparación sin un resultado numérico que pueda utilizar.

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;
}
  1. valid(45) y mean(8, 2)
  2. valid(0) y mean(7, 2)
  3. valid(91) y mean(8, 2)
  4. valid(90) y mean(7, 2)
Mostrar respuestaOcultar respuesta
Respuesta: B
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".

  1. «Open», «Close», «Mark», «Done»
  2. «Mark», «Open», «Close», «Done»
  3. «Open», «Mark», «Done», «Close»
  4. «Open», «Mark», «Close», «Done»
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un método tiene la cabecera public static void repeat(int count). ¿Qué valor recibe count en repeat((int) 3.9 + 2);?
  1. 3
  2. 5
  3. 6
  4. 5.9
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)));
  1. 24
  2. 42
  3. 30
  4. 18
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;
}
  1. Eliminar la rama else y mantener el return final.
  2. Sustituir el return del else por return n + 1;.
  3. Mover el return final al bucle, después del if/else.
  4. Cambiar la condición del if a n % 2 != 0.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un método auxiliar necesita el número almacenado en la variable local pages de main. ¿Cómo deben llegar los datos al método auxiliar?
  1. Declarar otra variable pages sin inicializar en el método auxiliar.
  2. Mover el método auxiliar debajo de main en la clase.
  3. Mantener la llamada al método auxiliar dentro del ámbito de pages.
  4. Añadir un parámetro y pasar pages como argumento.
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;
}
  1. 14
  2. 13
  3. 19
  4. 9
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?
  1. Llamar a printBorder(length, '#'); en su cuerpo.
  2. Añadir char symbol = '#' como parámetro predeterminado en la cabecera.
  3. Llamar a printBorder('#', length); en su cuerpo.
  4. Llamar a printBorder(length); en su cuerpo.
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);
  1. 6.5
  2. 6.0
  3. 7.5
  4. 7.0
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Dos bloques de código calculan áreas de rectángulos, uno con 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?
  1. public static void area(int width, int height)
  2. public static int area(int width)
  3. public static int area(int width, int height)
  4. public static int area()
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

¿Qué hace que public static int countItems(int limit) { return 0; } sea un método provisional útil?
  1. Demuestra que todos los recuentos de elementos son correctos.
  2. Elimina la necesidad de probar el método completado.
  3. Permite compilar las llamadas antes de terminar el cuerpo real.
  4. Proporciona a Java un valor predeterminado para el parámetro.
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");
    }
}
  1. Un método auxiliar debe colocarse encima de main.
  2. Un método auxiliar de impresión debe devolver un String.
  3. El método auxiliar está definido dentro de otro método.
  4. El nombre del método auxiliar debe empezar con mayúscula.
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;
}
  1. 3
  2. 0
  3. 3.6
  4. 4
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;
}
  1. true, después true
  2. false, después true
  3. false, después false
  4. true, después false
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);
  1. «parcel-checked»
  2. «checked»
  3. «parcelparcel»
  4. «parcel»
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)
  1. En main, en la línea 5.
  2. En printLoad, en la línea 15.
  3. En unitCount, en la línea 23.
  4. Después de que unitCount regresara a la línea 15.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Una clase declara 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?
  1. public static int describe(String name, int count)
  2. public static void describe(int count, String name)
  3. public static void describe(String title, int number)
  4. private static void describe(String name, int count)
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);
  1. 67.0
  2. 66.0
  3. «B!»
  4. 67
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Solo el código de la misma clase debe poder llamar a un método auxiliar. ¿Qué modificador de acceso debe utilizar su cabecera estática?
  1. public
  2. static
  3. void
  4. private
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.

  1. sumMultiples(2, 4) y después sumMultiples(5, 3)
  2. sumMultiples(4, 2) y después sumMultiples(3, 5)
  3. sumMultiples(2, 8) y después sumMultiples(5, 15)
  4. sumMultiples(2, 3) y después sumMultiples(5, 2)
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.

  1. Sobrescribir un count en el bucle; llamar a printReport(count, 5).
  2. Acumular los cinco recuentos devueltos; llamar a printReport(total, 5).
  3. Imprimir cada recuento devuelto; llamar después a printReport(0, 5).
  4. Sumar los números de los días en el bucle; llamar a printReport(total, 5).
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);
  1. 6:10
  2. 10:6
  3. 10:10
  4. 6:6
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);
  1. 9.5
  2. 7.5
  3. 3.0
  4. 8.0
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;
}
  1. 4
  2. 5
  3. 10
  4. 15
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);
  1. Mover solo println(total) al interior del bucle.
  2. Declarar int total; antes del bucle y eliminar su declaración interna.
  3. Mover int total = 0; antes del bucle y eliminar su declaración interna.
  4. Declarar int total = 0; después del bucle, antes de imprimir.
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).

  1. 7 y 21
  2. 21 y 21
  3. 5 y 15
  4. 7 y 7
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un programa sigue iniciando más llamadas sin dejar que terminen las existentes. ¿Qué error puede producirse cuando no queda espacio en la pila?
  1. ArithmeticException
  2. «missing return statement»
  3. «cannot find symbol»
  4. StackOverflowError
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; }
  1. El destino double selecciona (double, int) y almacena 9.0.
  2. La llamada es ambigua entre las dos versiones de tipos mixtos.
  3. El primer argumento int selecciona (int, double) y almacena 4.0.
  4. Se selecciona la versión con dos double y se almacena 13.0.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un cálculo de un sensor es útil, pero su método actual también imprime un mensaje de estado largo. Quien llama desde otro lugar necesita el número sin ese mensaje. ¿Qué diseño permite que ambos compartan un método de cálculo y elijan su propia salida?
  1. Añadir una segunda copia del cálculo sin la impresión.
  2. Cambiar el nombre del método existente para describir ambas acciones.
  3. Devolver el número y mover la impresión a quien genera el informe.
  4. Hacer público el método combinado para que ambos puedan utilizarlo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Dos bloques imprimen una etiqueta seguida de una línea por elemento. El primero imprime "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)?
  1. Imprimir label dentro de un bucle desde 0 mientras i < count; no imprimir números.
  2. Imprimir label una vez; recorrer desde 1 mientras i < count e imprimir i.
  3. Imprimir label una vez; recorrer desde 0 mientras i <= count e imprimir i.
  4. Imprimir label una vez; recorrer desde 1 mientras i <= count e imprimir i.
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?

  1. Esa división es exacta, por lo que el truncamiento no pierde ninguna parte fraccionaria.
  2. El método amplía ambos operandos int antes de realizar la división.
  3. Esa entrada prueba un cociente con una parte fraccionaria distinta de cero.
  4. El resultado se redondea después al número entero más cercano.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

51 Términos Clave, cada uno con su definición

A

Acumulador
Un acumulador es una variable que conserva un resultado acumulado mientras un bucle combina valores sucesivos en ese resultado.
Declara sum antes de un bucle para que cada iteración añada al total conservado de la pasada anterior.
Argumento
Un argumento es una expresión proporcionada en una llamada a método cuyo valor evaluado se pasa a un parámetro correspondiente.
En printRepeated("go", 4), los argumentos proporcionan el texto y el número de repeticiones.

Á

Ámbito
El ámbito de una variable es la región del texto del programa donde su nombre puede utilizarse legalmente para referirse a esa variable.
Un contador declarado en una cabecera for está dentro de su ámbito en ese bucle, pero no puede leerse después.

B

Bloque
Un bloque es un grupo de sentencias encerradas entre llaves que puede formar el cuerpo de un método, el cuerpo de un bucle o una rama condicional.
Declarar un contador dentro de un bloque if mantiene ese nombre local dentro de la llave de cierre del bloque.

C

Cabecera de método
Una cabecera de método declara el nombre, los modificadores, el tipo de retorno y los parámetros de un método antes de que comience su cuerpo.
La cabecera public static void greet() describe una acción a la que se puede llamar, sin datos de entrada ni valor devuelto.
Cadena String inmutable
Una cadena String inmutable es un String cuyo contenido no puede cambiar después de su creación; las operaciones de texto pueden producir otro String.
Concatenar "!" y asignar el resultado a un parámetro String deja sin cambios la referencia de quien llama.
Caso límite
Un caso límite prueba una entrada en un límite o junto a él, donde cambia el comportamiento esperado de un método, y ayuda a detectar errores en los extremos.
Para un rango válido de 0 a 1440, comprueba -1, 0, 1440 y 1441 como entradas separadas.
Código duplicado
El código duplicado repite sentencias iguales o casi iguales, lo que deja varios lugares que actualizar cuando cambia la tarea compartida.
Dos bucles de suma con distintos límites superiores a menudo pueden sustituirse por un método auxiliar y dos llamadas.
Coincidencia exacta
Una coincidencia exacta ocurre cuando los tipos de los argumentos ya coinciden con los tipos de parámetros de un método sin necesidad de conversión.
Con show(int) y show(double), show(9) tiene una coincidencia exacta con la versión int.
Conversión de ampliación
Una conversión de ampliación cambia un valor a un tipo más amplio permitido, lo que permite que un argumento int se ajuste a un parámetro double.
Pasar 12 a un parámetro double le proporciona 12.0 sin necesitar una conversión explícita de tipo.
Conversión de reducción
Una conversión de reducción cambia un valor numérico a un tipo más restringido y puede perder información; las llamadas a métodos no la realizan implícitamente.
Pasar 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
Una conversión explícita de tipo es una conversión escrita con un tipo de destino entre paréntesis antes de la expresión que se va a convertir.
La expresión (int) 4.9 proporciona 4 a un parámetro int al descartar la parte fraccionaria.
Cuerpo de método
Un cuerpo de método es el bloque encerrado entre llaves que contiene las sentencias ejecutadas cuando se llama al método.
La llamada entra en el cuerpo, ejecuta sus sentencias y después continúa en quien llamó y está esperando.

D

Desarrollo ascendente
El desarrollo ascendente construye y prueba primero métodos pequeños y después los combina en los pasos más grandes del programa.
Prueba una comprobación de validez y un método de formato por separado antes de utilizarlos en un programa completo de informes.
Desarrollo incremental
El desarrollo incremental añade y comprueba un pequeño fragmento de código funcional cada vez, lo que facilita encontrar la causa de un nuevo error.
Implementa un método auxiliar, compílalo, prueba resultados conocidos y después conéctalo con la siguiente parte.
Desbordamiento de pila
Un desbordamiento de pila ocurre cuando una cadena de llamadas a métodos necesita más espacio de pila del disponible, lo que produce StackOverflowError.
Las llamadas que siguen añadiendo marcos sin dejar que terminen pueden acabar agotando la pila.
Descomposición
La descomposición divide el problema de un programa en tareas significativas más pequeñas que pueden implementarse cada una como un método centrado en una tarea.
Un informe de un recorrido puede separar la obtención de datos de entrada, el cálculo de una velocidad y la presentación del resultado.
Diseño descendente
El diseño descendente comienza con el problema completo y divide repetidamente sus pasos en tareas más pequeñas con nombre o llamadas a métodos.
Planifica en 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
La extracción de método mueve un fragmento coherente de código a un método auxiliar, convirtiendo las entradas variables en parámetros y los resultados necesarios en valores de retorno.
Extraer un bucle de suma a sumUpTo(int n) deja su propio texto del informe a cargo de quien llama.

F

Firma de método
La firma de método para estos métodos es su nombre y los tipos de parámetros en orden; los tipos de retorno y los nombres de los parámetros no la distinguen.
Cambiar width por w deja area(int, int) sin cambios y no puede crear una nueva sobrecarga.

I

Inicialización
La inicialización da a una variable su valor inicial antes de que el código posterior la lea o actualice; las variables locales no tienen un valor inicial automático.
Escribir int total = 0; antes de un bucle de suma proporciona a la primera adición un total existente que actualizar.

J

Javadoc
Javadoc es documentación escrita en un comentario /** ... */ encima de una declaración, con etiquetas que describen los parámetros y los resultados.
Utiliza @param minutes para explicar un dato de entrada y @return para describir el texto con formato que produce.

L

Lista de parámetros
Una lista de parámetros es la secuencia ordenada de variables de entrada con tipo que aparece entre los paréntesis de la cabecera de un método.
La lista (int width, int height) requiere dos argumentos, que se corresponden primero con width y después con height.
Llamada a método
Una llamada a método es una expresión que nombra un método y proporciona sus argumentos entre paréntesis para invocar su cuerpo.
La sentencia printHeader(); ejecuta el método de impresión del encabezado en ese punto de quien llama.
Llamada ambigua
Una llamada ambigua es compatible con varias sobrecargas, pero ninguna es la coincidencia más específica, por lo que el compilador no puede seleccionar una.
Los pares (int, double) y (double, int) hacen que una llamada con dos argumentos int sea ambigua.
Llamada anidada
Una llamada anidada es una llamada a método utilizada dentro de otra llamada, por lo que su resultado debe obtenerse antes de que se ejecute el método externo.
En Math.max(sum(2, 6), 5), el resultado 8 se convierte en el primer argumento de Math.max.

M

Marco de pila
Un marco de pila contiene los parámetros y las variables locales de una llamada, así como información sobre dónde debe continuar después quien la llamó.
Dos llamadas pueden tener cada una un parámetro llamado minutes porque los parámetros ocupan marcos separados.
Método
Un método es un bloque de sentencias con nombre que realiza una tarea y se ejecuta cada vez que la ejecución del programa llega a una llamada a él.
Un método printHeader() puede imprimir el mismo encabezado de informe en varios lugares de un programa.
Método auxiliar
Un método auxiliar realiza una tarea más pequeña utilizada por otro método, lo que facilita la lectura y la construcción de la operación mayor.
Un método de informe puede llamar a un método de formato de duración en lugar de realizar el formato por sí mismo.
Método booleano
Un método booleano devuelve true o false, a menudo para responder a una pregunta que quien llama utiliza directamente como condición.
Una llamada como isEven(count) puede colocarse directamente dentro de los paréntesis de una sentencia if.
Método estático
Un método estático pertenece a una clase y puede llamarse sin crear un objeto de esa clase.
La llamada estática Math.abs(-6) utiliza el nombre de clase Math y devuelve el valor positivo 6.
Método privado
Un método privado solo puede ser llamado por código de su propia clase, por lo que un método auxiliar interno no está disponible para otras clases.
Declarar un cálculo como private static permite que su propia clase lo utilice sin ofrecer una llamada externa.
Método provisional
Un método provisional es un método temporal con su cabecera planificada y un cuerpo mínimo que permite compilar el código que lo rodea mientras está sin terminar.
Un return 0; temporal puede ocupar su lugar mientras se implementa y comprueba el cálculo real.
Método sobrecargado que delega
Un método sobrecargado que delega llama a otra versión de la misma operación, a menudo proporcionando un valor fijo para un argumento omitido.
Un método de impresión de líneas con un argumento puede llamar a la versión de dos argumentos con un carácter de guion fijo.

P

Parámetro
Un parámetro es una variable con tipo declarada en la cabecera de un método que recibe un valor cuando comienza una llamada concreta.
En printRepeated(String text, int times), text y times son los dos parámetros declarados.
Paso por valor
El paso por valor significa que cada parámetro recibe una copia del valor de su argumento, por lo que reasignar el parámetro deja intacta la variable de quien llama.
Un método auxiliar puede incrementar su parámetro int mientras el int original de quien llama permanece sin cambios.
Pila de llamadas
La pila de llamadas registra las llamadas a métodos sin terminar; la llamada más reciente se ejecuta arriba mientras quienes la llamaron esperan debajo.
Cuando 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
La refactorización cambia la estructura del código mientras conserva su comportamiento, por ejemplo, al sustituir cálculos repetidos por llamadas.
Compara los mismos datos de entrada antes y después de la extracción para comprobar que tanto los resultados como la salida permanecen iguales.
Referencia
Una referencia es un valor que apunta a un objeto; copiar ese valor puede permitir que dos variables se refieran al mismo objeto.
Pasar un String copia su referencia en el parámetro sin vincular las asignaciones de las dos variables.
Resolución de sobrecargas
La resolución de sobrecargas es el proceso por el que el compilador selecciona una versión adecuada de un método según el número y los tipos de argumentos de una llamada.
Un argumento int selecciona una sobrecarga int exacta antes que una versión que necesitaría conversión.
Retorno anticipado
Un retorno anticipado termina un método antes del final de su cuerpo, a menudo después de encontrar una coincidencia o tratar una condición de entrada.
Una búsqueda se detiene en cuanto se ejecuta return candidate;, aunque queden más candidatos en el bucle.

S

Sentencia inalcanzable
Una sentencia inalcanzable es código que Java determina que no puede ejecutarse, como una sentencia situada directamente después de return en el mismo bloque.
El compilador rechaza una impresión situada directamente después de un return incondicional en el mismo bloque.
Sentencia return
Una sentencia return termina la llamada al método actual y devuelve un valor en un método que no es void o ningún valor en un método void.
La sentencia return minutes * 60; termina el cálculo y proporciona el número de segundos.
Sobrecarga
La sobrecarga define métodos con el mismo nombre y distintas listas de parámetros para que una operación acepte distintas formas de entrada.
Dos métodos llamados max pueden aceptar dos int y tres int y mantener un solo significado para el nombre.

T

Tipo de retorno
Un tipo de retorno especifica el tipo de valor que un método proporciona a quien lo llama; void declara que no proporciona ningún valor.
Un método declarado como double average(int a, int b) promete un resultado double a quien lo llama.
Traza de la pila
Una traza de la pila es una lista impresa de los marcos de llamadas activos en un error, que muestra los nombres de los métodos y las ubicaciones en la cadena de llamadas.
El primer marco localiza el fallo y las líneas inferiores muestran qué métodos llamaron hasta llegar a él.

Ú

Último en entrar, primero en salir
Último en entrar, primero en salir es el orden de la pila en el que la llamada sin terminar más reciente se completa antes de que se reanude quien la llamó y está esperando.
Un método auxiliar interno retorna antes de que el método auxiliar externo pueda terminar de utilizar ese valor devuelto.

V

Valor centinela
Un valor centinela es un resultado especial acordado que se utiliza para señalar una condición, como que una búsqueda no encuentre ningún candidato coincidente.
Devolver -1 después de una búsqueda puede indicar «no encontrado» cuando -1 no puede ser una coincidencia válida.
Valor de retorno
Un valor de retorno es el resultado que un método envía al lugar de la llamada, donde puede almacenarse o utilizarse en otra expresión.
Después de int total = sum(6, 8);, el 14 devuelto se almacena en la variable total de quien llama.
Variable local
Una variable local se declara dentro de un método o bloque y pertenece a la ejecución de esa región, no al programa completo.
El total local de un método auxiliar es independiente de una variable local de otro método también llamada total.
void
La palabra clave de Java void declara que un método no devuelve ningún valor, aunque su cuerpo realice acciones como imprimir.
Una llamada void a printTotal no puede ocupar el lado derecho de una asignación a un int solo porque imprima un número.

Sobre esta unidad

Por StudeliInformar de un error

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.

Comenzar