Tabla de Contenidos

02.1 - Fundamentos de programación en Java

1. Lenguajes de programación

Podemos clasificar los lenguajes de programación atendiendo a distintos criterios

1.1 Según su nivel de abstracción

Ejemplo de código máquina:

0010 0000 1001 1001 1000 1110

Ejemplo de lenguaje ensamblador:

MOV R1, DPL
CJNE R1, #78H, T05SEG
RET

1.2 Según cómo gestionan los tipos de sus datos

1.3 Según su forma de ejecución

2. Elementos de un lenguaje de programación

Hay una serie de elementos que están presentes en casi todo lenguaje de programación:

3. Introducción al lenguaje Java

Java es un lenguaje de programación de alto nivel, de propósito general y con una sintaxis ampliamente derivada de C/C++. Fue creado originalmente por Sun Microsystems (actualmente propiedad de Oracle) en 1995.

Entre sus pilares fundamentales destacan:

Java es un lenguaje de tipado estático y fuertemente tipado (aunque realiza pequeñas conversiones implícitas seguras, como concatenar números a cadenas de texto).

public class Tipado {

    static void main() {
        int a = 5;
        // a = "Hola"; // ERROR de compilación: No se puede asignar un String a una variable int.

        String b = "Texto: ";
        IO.println(b + a); // Concatenación implícita: convierte 'a' a String ("Texto: 5").
    }
}

3.1 Compilación y ejecución de aplicaciones Java

Los archivos de código fuente en Java tienen la extensión .java y su nombre debe coincidir exactamente con la clase principal que contienen.

public class HolaMundo {

        static void main() {
                IO.println("Hola Mundo");
        }
}

Existen dos formas de ejecutar este programa desde la consola:

1. Ejecución directa en un solo paso: Ideal para pruebas rápidas. Compila en memoria y ejecuta el resultado de forma transparente:

java HolaMundo.java

2. Proceso tradicional en dos pasos (entornos de producción):

1. Compilar el código fuente a bytecode (genera el archivo HolaMundo.class):

javac HolaMundo.java

2. Ejecutar el bytecode compilado en la JVM:

java HolaMundo

Al ejecutar con el comando java un archivo ya compilado, no debemos poner la extensión .class, solo el nombre de la clase. Esta ejecución es más rápida porque no requiere recompilar el código.

3.2 Generación de archivos .class

El compilador de Java genera un archivo .class por cada clase definida en nuestro código fuente, independientemente de si están en el mismo archivo .java o en archivos separados.

public class HolaMundo2 {

    static void main() {
        IO.println("Hola Mundo 2");
    }
}

class HolaMundo3 {

    static void main() {
        IO.println("Hola Mundo 3");
    }
}

Al ejecutar javac HolaMundo2.java, se generarán dos archivos independientes: HolaMundo2.class y HolaMundo3.class.

Regla de visibilidad de archivos: Un archivo .java solo puede contener una clase pública (public) como máximo, y el nombre del archivo debe coincidir exactamente con el nombre de dicha clase.

3.3 Estructura de una aplicación Java

Vamos a ver la estructura del ejemplo anterior HolaMundo.java:

public class HolaMundo {

        static void main() {
                IO.println("Hola Mundo");
        }
}

3.4 Secuencia de instrucciones

Las instrucciones se ejecutan secuencialmente (de arriba a abajo) y deben terminar obligatoriamente con punto y coma (;).

static void main() {
    IO.println("Primera instrucción");
    IO.println("Segunda instrucción");
}

3.5 Indentación del código

Aunque Java no obliga a sangrar el código para que compile (a diferencia de Python), la indentación es fundamental para garantizar la legibilidad del proyecto. Se recomienda usar 4 espacios por cada nivel de anidamiento.

Ejemplo con correcta indentación:

public class HolaMundo {
    
    static void main() {
        IO.println("Código fácil de leer");
    }
}

3.6 Comentarios

Los comentarios son anotaciones dentro del código fuente que el compilador ignora por completo. Su objetivo es explicar la lógica del programa, añadir notas aclaratorias o generar documentación técnica.

En Java podemos escribir comentarios de tres formas:

/**
 * Comentario de documentación (JavaDoc).
 * Muestra información sobre la clase o el autor.
 */
public class HolaMundo {

    static void main() {
        /*
         * Comentario de bloque o multilínea.
         * Útil para detallar algoritmos o bloques
         * de código complejos.
         */
        
        // Comentario de una línea: explica la instrucción siguiente
        IO.println("Hola mundo");
    }
}

No abuses de los comentarios: Como indica Robert C. Martin en su libro Código limpio (Clean Code), el mejor comentario es el que no hace falta escribir. Es preferible escribir código expresivo y autoexplicativo (utilizando buenos nombres de variables y métodos) antes que llenar el programa de comentarios redundantes.
Limpia el código “muerto”: Durante la fase de desarrollo es habitual comentar bloques de código para realizar pruebas. Es importante eliminar todo ese código comentado antes de finalizar y entregar el proyecto, ya que genera ruido y confunde a otros programadores.

4. Elementos básicos en Java

4.1 Variables

Una variable es una posición de memoria con un nombre simbólico asignado donde se almacena un valor susceptible de cambiar a lo largo del programa. Una constante, por el contrario, mantiene un valor fijo e inmutable durante toda la ejecución.

Declaración e inicialización

Para utilizar una variable en Java debemos especificar su tipo de dato seguido de su nombre (identificador). Podemos reservar el espacio en memoria (declarar) y asignarle un valor (inicializar) en pasos separados o en una sola línea:

static void main() {
    // 1. Declaración (reserva espacio en memoria, sin valor inicial)
    int edad;

    // 2. Inicialización (asignación del primer valor)
    edad = 25;

    // 3. Declaración e inicialización simultánea (lo más habitual)
    double precio = 19.99;
    boolean activo = true;
}

En Java, las variables locales deben inicializarse antes de ser utilizadas. Intentar leer o imprimir el valor de una variable que no ha sido inicializada provocará un error de compilación.

Tipos primitivos

Java maneja 8 tipos de datos primitivos que representan valores simples (enteros, decimales, caracteres o booleanos).

Tipo Tamaño (bits) Descripción Valor por defecto
byte 8 Entero muy pequeño con signo $[-128, 127]$ $0$
short 16 Entero corto con signo $[-32768, 32767]$ $0$
int 32 Entero estándar $[-2^{31}, 2^{31}-1]$ $0$
long 64 Entero largo $[-2^{63}, 2^{63}-1]$ $0L$
float 32 Decimal en coma flotante de precisión simple $0.0f$
double 64 Decimal en coma flotante de precisión doble $0.0d$
char 16 Carácter individual en formato Unicode $'\u0000'$
boolean 1 Valor lógico (true o false) false

Inferencia de tipos (var)

Desde Java 10, es posible omitir la declaración explícita del tipo en variables locales utilizando la palabra reservada var. El compilador deducirá el tipo basándose en el valor asignado:

var edad = 25;           // Compila como int
var sueldo = 1250.50;    // Compila como double
var texto = "Hola";      // Compila como String

Por defecto, Java interpreta los literales enteros como int y los decimales como double. Si necesitas asignar un valor de tipo float o long, debes añadir un sufijo al literal:
float pi = 3.1416f;           // Requiere 'f' para no ser tratado como double
long distancia = 3000000000L; // Requiere 'L'

Conversión de tipos (Cast)

Cuando necesitamos convertir el valor de un tipo primitivo a otro, utilizamos la conversión explícita mediante el operador de cast: (tipo) expresion.

public class Cast {

    static void main() {
        // Cast directo (truncamiento)
        double precioDouble = 19.99;
        int precioEntero = (int) precioDouble; // Pierde los decimales -> 19

        // Evitar división entera no deseada
        int a = 9;
        int b = 2;
        float resultadoIncorrecto = (float) (a / b); // Divide como int (4) y lo convierte a float -> 4.0f
        float resultadoCorrecto = (float) a / b;     // Convierte 'a' a float (9.0f) y divide -> 4.5f
    }
}

El operador (tipo) solo funciona entre tipos primitivos compatibles. Para convertir de String a un tipo numérico, debemos usar los métodos parse de sus respectivas clases envoltorio (wrapper classes):
String textoNumero = "42";
int numero = Integer.parseInt(textoNumero);
double decimal = Double.parseDouble("3.14");

Nombres y reglas de estilo

Reglas de sintaxis
Buenas prácticas

4.2 Constantes

Las constantes almacenan información que no debe cambiar durante la ejecución. Se definen anteponiendo la palabra reservada final. Por convención, sus nombres se escriben en MAYÚSCULAS_CON_GUION_BAJO.

public class Constantes {

    static void main() {
        final double VELOCIDAD_LUZ = 299792.458; // en km/s
        final float PI = 3.1416f;

        // VELOCIDAD_LUZ = 300000.0; // ERROR de compilación: No se puede reasignar una variable final
    }
}

4.3 Operadores

Operador de asignación y caracteres de escape

El operador principal de asignación es el signo igual (=). Según el tipo de dato asignado, debemos considerar ciertas reglas sintácticas:

static void main() {
    char letra = 'A';
    boolean activo = true;
    String frase = "Dijo: \"Hola mundo\""; // Carácter de escape \"
}

Operadores aritméticos y de asignación compuesta

Java ofrece operadores aritméticos básicos: suma (+), resta (-), multiplicación (*), división (/) y módulo o resto entero (%). Pueden combinarse con el operador de asignación para acortar instrucciones:

Operador Ejemplo Equivalencia
+= a += b; a = a + b;
-= a -= b; a = a - b;
*= a *= b; a = a * b;
/= a /= b; a = a / b;
%= a %= b; a = a % b;

Operadores unarios

Operan sobre un único valor para modificar su signo, incrementarlo, decrementarlo o negarlo:

public class OperadoresUnarios {

    static void main() {
        int a = 3;
        IO.println("Post-incremento (a++): " + a++); // Muestra 3, 'a' pasa a ser 4
        IO.println("Valor tras a++: " + a);          // Muestra 4

        a = 3;
        IO.println("Pre-incremento (++a): " + ++a);  // 'a' pasa a ser 4, Muestra 4
    }
}

Operadores relacionales

Comparan dos operandos y devuelven un valor booleano (true o false): == (igual a), != (distinto de), < (menor que), > (mayor que), (menor o igual) y >= (mayor o igual).

Un error muy frecuente es confundir la asignación (=) con la comparación de igualdad (==):
int a = 5;
int b = 2;

// IO.println(a = b);  // Asigna 2 a 'a' e imprime 2. ¡Sobrescribe la variable!
IO.println(a == b); // Compara si 'a' es igual a 'b' e imprime false.

Operadores lógicos

Permiten combinar múltiples condiciones booleanas:

static void main() {
    int edad = 20;
    boolean tieneCarnet = true;

    boolean puedeConducir = edad >= 18 && tieneCarnet; // true
}

5. Estructuras de control

5.1 Entrada y Salida de datos con la clase IO

A partir de Java 25 utilizamos la clase IO para interactuar con la consola sin necesidad de realizar importaciones adicionales.

Salida por consola

Entrada por teclado

El método IO.readln() pausa la ejecución hasta que el usuario escribe un texto y pulsa Intro. Siempre retorna los datos en forma de cadena (String). Si se requiere un valor numérico, debemos realizar el parseo correspondiente:

public class EntradaSalida {

    static void main() {
        String nombre = IO.readln("Introduce tu nombre: ");
        int edad = Integer.parseInt(IO.readln("Introduce tu edad: "));

        IO.println("Hola " + nombre + ", tienes " + edad + " años.");
    }
}

5.2 Estructuras de selección

Permiten ejecutar un conjunto de instrucciones u otro en función del resultado de evaluar una condición lógica que devuelve un valor booleano (true o false). En Java existen tres estructuras de selección: if-else, switch y el operador ternario.

La sentencia if-else

La sentencia if evalúa una condición. Si esta resulta verdadera (true), se ejecuta el bloque de código delimitado entre llaves {}. En caso contrario, el bloque se omite.

public class SentenciaIf {

    static void main() {
        int number = 3;

        if (number < 5) {
            IO.println("El número es menor que 5");
        }
        IO.println("Fin del programa");
    }
}

Atención a los límites de las condiciones: Evaluar si un número es menor (<) no es lo mismo que evaluar si es menor o igual (). Para number = 5, la condición number < 5 devolverá false. Un porcentaje elevado de los errores en programación principiante proviene de un mal ajuste en los operadores de comparación.
Condiciones compuestas

Podemos combinar varias expresiones lógicas en una sola condición utilizando los operadores lógicos && (AND) y || (OR):

if (number > 2 && number < 5) {
    IO.println("El número está estrictamente entre 2 y 5");
}

La cláusula else y else-if

Para ejecutar una alternativa cuando la condición resulte falsa, añadimos el bloque else. Esto evita tener que evaluar condiciones mutuamente excluyentes dos veces de forma ineficiente.

if (number < 5) {
    IO.println("El número es menor que 5");
} else {
    IO.println("El número es mayor o igual que 5");
}

Si necesitamos evaluar múltiples alternativas en cadena, utilizamos else if:

if (number < 5) {
    IO.println("El número es menor que 5");
} else if (number < 8) {
    IO.println("El número está en el rango [5, 8)");
} else if (number < 10) {
    IO.println("El número está en el rango [8, 10)");
} else {
    IO.println("El número es mayor o igual que 10");
}

Que un programa funcione no significa que sea eficiente. Encadenar múltiples bloques if independientes en lugar de usar else if obliga a la CPU a evaluar todas las condiciones, reduciendo el rendimiento en programas de gran escala.

La sentencia switch

Cuando debemos comparar una misma variable contra múltiples valores constantes, la sentencia switch ofrece una alternativa mucho más limpia, estructurada y legible que encadenar múltiples bloques else if.

En el Java moderno, switch no solo funciona como una instrucción de control de flujo, sino también como una expresión capaz de devolver un valor directamente a una variable.

Sintaxis básica con operador flecha (->)

La forma estándar de escribir un switch utiliza el operador flecha (→). Esta sintaxis tiene dos ventajas clave:

int day = 3;

switch (day) {
    case 1, 2, 3, 4, 5 -> IO.println("Entre semana / Laborable");
    case 6, 7          -> IO.println("Fin de semana");
    default            -> IO.println("Día no válido");
}

Si un caso requiere ejecutar más de una instrucción, se delimita mediante un bloque de llaves {}:

int option = 1;

switch (option) {
    case 1 -> {
        IO.println("Iniciando el proceso de copia...");
        IO.println("Copia realizada con éxito.");
    }
    case 2  -> IO.println("Mostrando configuración...");
    default -> IO.println("Opción no reconocida.");
}

Switch como expresión (devolución de valores)

Un switch puede utilizarse directamente a la derecha de una asignación para calcular y retornar un valor que se guarda en una variable:

int month = 2;

String season = switch (month) {
    case 12, 1, 2  -> "Invierno";
    case 3, 4, 5   -> "Primavera";
    case 6, 7, 8   -> "Verano";
    case 9, 10, 11 -> "Otoño";
    default        -> "Mes no válido";
}; // Recuerda incluir el punto y coma final por ser una asignación de variable

Exhaustividad obligatoria: Cuando el switch se utiliza como expresión para devolver un valor, debe garantizarse que todos los casos posibles estén cubiertos. Por este motivo, la cláusula default es casi siempre obligatoria.
Bloques multilínea y la palabra reservada yield

Cuando utilizamos un switch como expresión y uno de los casos necesita ejecutar varias líneas dentro de un bloque {}, no podemos devolver el valor directamente tras la flecha. En su lugar, utilizamos la palabra clave yield para indicar qué valor retorna ese bloque:

int code = 404;

String statusText = switch (code) {
    case 200 -> "OK";
    case 404 -> {
        IO.println("Registrando alerta: recurso no encontrado en el servidor.");
        yield "Not Found"; // Devuelve este resultado para el caso 404
    }
    case 500 -> "Internal Server Error";
    default  -> "Unknown Code";
};

Tipos de datos compatibles

En Java, no todos los tipos de datos pueden ser evaluados dentro de un switch. Los tipos permitidos son:

String role = "ADMIN";

switch (role) {
    case "ADMIN", "SUPERUSER" -> IO.println("Acceso total otorgado");
    case "USER"              -> IO.println("Acceso limitado a lectura");
    default                  -> IO.println("Acceso denegado");
}

Operador ternario

El operador ternario (?:) es una forma compacta de representar una estructura if-else simple en una sola línea de código.

Sintaxis
variable = (condicion) ? valor_si_verdadero : valor_si_falso;

Por ejemplo, este bloque condicional:

String message;
if (age >= 18) {
    message = "Mayor de edad";
} else {
    message = "Menor de edad";
}

Se simplifica a:

String message = (age >= 18) ? "Mayor de edad" : "Menor de edad";

5.3 Estructuras de iteración (Bucles)

Las iteraciones o bucles permiten repetir un bloque de código mientras una determinada condición sea verdadera. Java proporciona tres estructuras iterativas principales: while, do-while y for.

El bucle while

Evalúa la condición antes de cada iteración. Si es true, ejecuta el bloque de código; si es false, el bucle finaliza.

public class BucleWhile {

    static void main() {
        int counter = 1;

        while (counter < 10) {
            IO.println(counter);
            counter++; // Incremento obligatorio para evitar bucle infinito
        }
    }
}

Riesgo de bucle infinito: Si dentro del cuerpo del bucle no modificamos el valor de las variables que intervienen en la condición (por ejemplo, omitiendo counter++), la condición siempre será true y el programa quedará atrapado consumiendo recursos.

El bucle do-while

A diferencia del bucle while, el bucle do-while evalúa la condición al final de la iteración. Esto garantiza que el bloque de código se ejecutará al menos una vez, independientemente de si la condición es verdadera o falsa desde el inicio.

int number = 10;

// Se ejecuta 1 vez aunque 10 no es menor que 10
do {
    IO.println("Bucle do-while: " + number);
    number++;
} while (number < 10);

number = 10;

// No se ejecuta ninguna vez
while (number < 10) {
    IO.println("Bucle while: " + number);
    number++;
}

El bucle for

Se utiliza principalmente cuando conocemos de antemano el número exacto de iteraciones que debemos realizar. Agrupa en una sola línea la inicialización, la condición de parada y el paso de actualización.

Estructura de la cabecera for
for (inicialización; condición; actualización)

public class BucleFor {

    public static void main(String[] args) {
        for (int i = 1; i < 10; i++) {
            IO.println(i);
        }
    }
}

Control de flujo: break y continue

Las sentencias break y continue permiten alterarle el flujo normal de ejecución dentro de cualquier tipo de bucle:

for (int i = 0; i < 10; i++) {
    if (i > 4) {
        break; // Detiene el bucle cuando i llega a 5
    }
    IO.println(i);
}

for (int i = 0; i < 10; i++) {
    if (i == 4) {
        continue; // Omite imprimir el valor 4 y continúa con i = 5
    }
    IO.println(i);
}

Bucles anidados

Un bucle anidado es un bucle colocado dentro del cuerpo de otro bucle. Por cada iteración del bucle exterior, el bucle interior ejecutará completas todas sus iteraciones.

Un ejemplo clásico es la generación de las tablas de multiplicar del 1 al 9:

for (int i = 1; i <= 9; i++) {
    IO.println("--- Tabla del " + i + " ---");
    for (int j = 1; j <= 10; j++) {
        IO.println(i + " x " + j + " = " + (i * j));
    }
}

Aunque es posible anidar múltiples niveles de bucles, el abuso de esta técnica incrementa exponencialmente la complejidad temporal de la aplicación ($O(n^2)$, $O(n^3)$) y dificulta la lectura del código.

¿Qué bucle elegir?

Escenario Bucle recomendado
Refleja un número conocido de iteraciones for
El número de iteraciones es indefinido, pero debe ejecutarse al menos una vez do-while
El número de iteraciones es indefinido y puede que nunca deba ejecutarse while

6. Estructuras de datos estáticas

6.1 String

Un String representa una cadena de caracteres (texto). Aunque en Java es un objeto, conceptualmente se comporta como una secuencia de caracteres inmutable y de tamaño fijo.

// Inicialización directa (literal)
String nombre = "Ana";

// Mediante la palabra clave new (crea un objeto explícito en memoria)
String apellido = new String("García");

Inmutabilidad

Una propiedad fundamental de los String es que son inmutables: una vez creada la cadena en memoria, su contenido no se puede modificar.

Cualquier método que apliquemos sobre un String (convertir a mayúsculas, reemplazar letras, etc.) no modifica el texto original, sino que devuelve un nuevo String con la transformación.

String texto = "hola";
texto.toUpperCase(); // NO modifica la variable 'texto'
IO.println(texto);   // Muestra "hola"

// Para conservar el resultado, debemos reasignarlo a la variable:
texto = texto.toUpperCase();
IO.println(texto);   // Muestra "HOLA"

Acceso y longitud

A diferencia de los arrays donde usamos corchetes [] y la propiedad .length, en los String utilizamos métodos:

String mensaje = "Java";

IO.println("Longitud: " + mensaje.length());            // Muestra 4
IO.println("Primer carácter: " + mensaje.charAt(0));     // Muestra 'J'
IO.println("Último carácter: " + mensaje.charAt(mensaje.length() - 1)); // Muestra 'a'

Comparación de Strings

En Java NUNCA debemos usar el operador == para comparar el contenido de dos cadenas. El operador == comprueba si ambas variables apuntan a la misma posición de memoria, no si contienen las mismas letras.

Para comparar texto debemos usar el método .equals() o .equalsIgnoreCase() (para ignorar mayúsculas y minúsculas):

String texto1 = IO.readln("Introduce una palabra: "); // Ejemplo: "hola"
String texto2 = "hola";

// INCORRECTO: Compara referencias de memoria (daría false casi siempre)
if (texto1 == texto2) { 
    IO.println("Apuntan al mismo objeto en memoria");
}

// CORRECTO: Compara el contenido de las cadenas
if (texto1.equals(texto2)) {
    IO.println("El texto es exactamente igual");
}

// Compara ignorando mayúsculas y minúsculas
if (texto1.equalsIgnoreCase("HOLA")) {
    IO.println("Coinciden sin importar mayúsculas/minúsculas");
}

Métodos principales de String

La clase String dispone de multitud de métodos para manipular texto de forma sencilla:

Método Descripción Ejemplo Resultado
contains(texto) Comprueba si contiene una subcadena “Programación”.contains(“grama”) true
indexOf(texto) Devuelve la posición de la primera aparición (o -1 si no existe) “Java”.indexOf(“v”) 2
substring(inicio, fin) Extrae el texto desde inicio hasta fin - 1 “Elefante”.substring(0, 3) “Ele”
toLowerCase() / toUpperCase() Convierte todo el texto a minúsculas / mayúsculas “Java”.toLowerCase() “java”
replace(viejo, nuevo) Reemplaza un texto por otro “Casa”.replace(“a”, “o”) “Coso”
trim() Elimina espacios en blanco al inicio y al final “ Hola ”.trim() “Hola”

Recorrido y conversión a char[]

Podemos recorrer un String carácter a carácter utilizando un bucle for con charAt(), o convirtiéndolo directamente a un array de caracteres (char[]):

String palabra = "Algoritmo";

// Opción 1: Recorrido con bucle for tradicional y charAt()
for (int i = 0; i < palabra.length(); i++) {
    char letra = palabra.charAt(i);
    IO.println("Posición " + i + ": " + letra);
}

// Opción 2: Convertir a char[] y recorrer con for-each
char[] letras = palabra.toCharArray();
for (char letra : letras) {
    IO.print(letra + " ");
}
IO.println("");

6.2 Arrays

Los array permiten almacenar un conjunto finito de elementos del mismo tipo con un tamaño fijo asignado desde su creación.

Las posiciones se numeran desde la 0 hasta tamaño - 1. Para acceder o modificar un valor usamos los corchetes [].

        int[] numbers;

        numbers = new int[10];
        
        //int[] numbers = new int[10];

Para almacenar valores en cada una de las posiciones del array, usamos corchetes ([]) indicando en su interior la posición en la que queremos leer o escribir.

numbers[3] = 10;

Para acceder a los datos de un array accedemos mediante nombre[posicion].

        int number;

        number = numbers[3];

Propiedad length y recorridos

La propiedad length nos devuelve el número total de elementos. Podemos recorrer el array mediante un bucle for convencional o con un bucle for-each:

// Recorrido con for tradicional
for (int i = 0; i < numbers.length; i++) {
    IO.println("Índice " + i + ": " + numbers[i]);
}

// Recorrido con for-each (más limpio para lectura)
for (int number : numbers) {
    IO.println(number);
}

Inicializar array:

        int[] numbers = new int[5];
        
        for(int i=0; i<numbers.length; i++) {
            numbers[i] = Integer.parseInt(IO.readln("Introduce un número entero: "));
        }

Otra forma de inicializar un array es definiendo sus valores como una lista separada por comas encerrada entre llaves. Ésto lo debemos hacer a la hora de la declaración del array, y no hace falta indicarle la longitud, ya que se lo indicamos con el número de elementos que le pasemos:

int[] numbers = {1, 3, 312, 15, 69, 7, 8, 9, 0, 1};

Arrays multidimensionales

Podemos declarar un array de más de una dimensión (como tablas o matrices):

// Inicialización directa
int[][] table = {
    {3, 5, 6},
    {2, 4, 9}
};

// Recorrido con bucles anidados
for (int[] row : table) {
    for (int cell : row) {
        IO.print(cell + " ");
    }
    IO.println("");
}

Ejercicios

Ejercicio 1.a

Crea un programa que calcule el área de un triángulo con base $5$ y altura $10$ ($\text{Área} = \frac{\text{base} \cdot \text{altura}}{2}$). La base y la altura deben ser constantes de tipo entero (int) y el área una variable del mismo tipo.

Ejercicio 1.b

Modifica el tipo de la variable área a float y la altura a $9$. Comprueba si el resultado coincide con el cálculo manual. Haz las modificaciones necesarias en la operación sin cambiar el tipo de las constantes para obtener el resultado decimal exacto.

Ejercicio 1.c

Modifica las constantes del Ejercicio 1.a a tipo decimal (float o double) para obtener la solución exacta directamente.

Ejercicio 1.d

Haz que la base y la altura sean introducidas dinámicamente por el usuario a través de teclado mediante IO.readln().

Ejercicio 2.a

Escribe un programa que solicite dos números decimales (float) al usuario e imprima su suma, resta, multiplicación, división y módulo (resto).

Ejercicio 2.b

Modifica el programa anterior para que los resultados de las operaciones se muestren convertidos a entero (int) mediante *casting*, sin cambiar el tipo original de las variables de entrada.

Ejercicio 2.c

Utiliza el método de formateo String.format(“%.2f”, valor) para mostrar el resultado de la división con exactamente dos decimales.

Ejercicio 3.a

Crea un programa que solicite un número al usuario y calcule su raíz cuadrada empleando el método adecuado de la clase Math.

Ejercicio 3.b

Aplica formato a la salida del ejercicio anterior para presentar la raíz cuadrada con tres decimales.

Ejercicio 4

Escribe un programa que solicite por teclado una base y un exponente (números enteros) y muestre por pantalla el resultado de elevar la base a dicho exponente empleando la clase Math. Muestra el resultado formateado a 2 decimales.

Ejercicio 5

Dado el siguiente literal de cadena con espacios superfluos: String mensaje = “ hola mundo ”;, crea un programa que imprima dicho mensaje completamente en mayúsculas y habiendo eliminado los espacios sobrantes de los extremos.

Ejercicio 6.a

Utiliza la clase java.util.Random o Math.random() para generar y mostrar por pantalla un número entero aleatorio entre $0$ y $9$.

Ejercicio 6.b

Modifica el ejercicio anterior para que el usuario introduzca por teclado el límite mínimo y máximo entre los cuales se generará el entero aleatorio.

Ejercicio 7.a

Escribe un programa que pregunte la edad por teclado y muestre el mensaje “Puedes pasar” si es mayor o igual a 18 años, o “No puedes pasar” en caso contrario. Usa if-else.

Ejercicio 7.b

Modifica el ejercicio anterior para resolverlo utilizando únicamente una sentencia if (sin cláusula else).

Ejercicio 7.c

Reescribe la lógica del ejercicio 1.a utilizando el operador ternario.

Ejercicio 8.a

Crea un programa que solicite dos números por teclado y determine cuál de los dos es el mayor.

Ejercicio 8.b

Resuelve el cálculo del mayor de dos números del ejercicio anterior utilizando el operador ternario.

Ejercicio 9.a

Escribe un programa que determine si un número entero introducido por teclado es par o impar utilizando if-else.

Ejercicio 9.b

Modifica el programa anterior para asignar el resultado (true si es par, false si es impar) a una variable booleana llamada isEven mediante el operador ternario.

Ejercicio 10.a

Escribe un programa que pida un color por teclado:

Ejercicio 10.b

Modifica el programa anterior para que la comparación no sea sensible a mayúsculas o minúsculas (ej. “Rojo” o “ROJO” funcionarán igual que “rojo”).

Ejercicio 10.c

Añade al programa anterior la limpieza de espacios en blanco al inicio y al final del texto introducido por el usuario (ej. “ rojo ” debe funcionar correctamente).

Ejercicio 11.a

Escribe un programa que calcule el factorial de un número entero positivo introducido por el usuario utilizando un bucle while.

Ejercicio 11.b

Reescribe el programa del cálculo del factorial utilizando un bucle for.

Ejercicio 12.a

Crea un programa que pida un número entero positivo $N$ por pantalla y muestre todos los números pares comprendidos entre $1$ y $N$ utilizando un bucle while.

Ejercicio 12.b

Reescribe el ejercicio anterior utilizando un bucle for.

Ejercicio 12.c

Modifica el ejercicio anterior utilizando la sentencia continue dentro del bucle para filtrar los números impares.

Ejercicio 12.d

Formatea la salida del ejercicio anterior para que muestre los números en una sola línea separados por comas:

Escribe un número: 17
2, 4, 6, 8, 10, 12, 14, 16

Ejercicio 13.a

Escribe un programa que encuentre el primer múltiplo de un número dado en un rango (excluyendo el propio número). No utilices la sentencia break.

Ejercicio 13.b

Modifica el programa anterior para detener la búsqueda del múltiplo mediante el uso de la sentencia break.

Ejercicio 14.a

Muestra la tabla de multiplicar de un número introducido por el usuario.

Ejercicio 14.b

Amplía el ejercicio anterior para que, tras cada multiplicación, calcule y muestre el sumatorio acumulado desde 1 hasta el resultado obtenido:

Escribe un número: 3
3 * 1 = 3  -> Suma (1..3): 6
3 * 2 = 6  -> Suma (1..6): 21
3 * 3 = 9  -> Suma (1..9): 45
...

Ejercicio 15.a

Crea un programa que muestre un menú interactivo con 3 opciones y muestre la opción elegida:

1.- Opción A
2.- Opción B
3.- Opción C
--------------------
Opción: 2
Ha elegido la Opción B

Ejercicio 15.b

Modifica el menú anterior para añadir la opción “0.- Salir”. El programa debe ejecutarse repetidamente y no finalizará hasta que el usuario introduzca el número $0$.