Currículo: esta unidad cubre parte de los saberes básicos del Bloque A – Programación (PRYC.2.A.1) correspondiente a 2º Bachillerato. Además, se evalúan los criterios que puedes encontrar al final de esta página.
Tabla de contenidos
- 1. Del algoritmo al código
- 2. Tipos de lenguajes de programación
- 3. Estructura básica de un programa
- 4. Tipos básicos de datos
- 5. Variables y constantes
- 6. Operadores y expresiones
- 7. Comentarios
- 8. Estructuras de control condicionales
- 9. Estructuras de control iterativas
- 10. Estructuras de datos
- 11. Funciones
1. Del algoritmo al código
En el tema anterior aprendimos a pensar como programadores, es decir, a analizar un problema, dividirlo en partes más pequeñas y expresar la solución mediante diagramas de flujo y pseudocódigo. Ahora llega el momento de transformar esas ideas en algo real, en algo que el ordenador pueda ejecutar. En otras palabras, pasamos del pensamiento al código.
Cuando escribimos un programa, lo que hacemos es traducir nuestro razonamiento lógico a un lenguaje que la máquina pueda entender. Esa traducción no se hace con frases normales, sino con lenguajes de programación, diseñados para ser precisos, estructurados y sin ambigüedades. El ordenador no interpreta intenciones: solo sigue exactamente las instrucciones que recibe.
Si a un robot doméstico le dices «Hazme un bocadillo de jamón», para nosotros está claro lo que queremos, pero para el robot no. Tendríamos que explicarle paso a paso:
- Coge dos rebanadas de pan.
- Abre el paquete de jamón.
- Coloca el jamón entre las rebanadas.
- Cierra el bocadillo.
Y aún así es posible que necesitara instrucciones más precisas para lograr lo que esperamos. Solo con instrucciones precisas el robot podría hacerlo correctamente. Eso es lo que hace un programador: dar instrucciones precisas, ordenadas y sin ambigüedad para que el ordenador realice una tarea.
En este tema trabajaremos con Java como lenguaje de aprendizaje. Es un lenguaje muy utilizado tanto en la enseñanza como en el mundo profesional, y su sintaxis nos obliga a ser cuidadosos, organizados y claros, algo muy positivo en esta etapa.

Aprenderemos paso a paso a escribir programas completos, desde los más simples (mostrar un mensaje o hacer una suma) hasta los que manejan estructuras de datos, toman decisiones, repiten acciones o leen información de archivos.
2. Tipos de lenguajes de programación
Ya hemos visto que para que un ordenador realice cualquier tarea, necesita recibir instrucciones precisas. Pero esas instrucciones pueden escribirse de distintas formas, unas más cercanas al lenguaje que entiende la máquina y otras más próximas al lenguaje humano. De ahí surgen los distintos niveles de lenguajes de programación, que podemos imaginar como una escalera: cuanto más subimos, más fácil es para nosotros entender y escribir el código; cuanto más bajamos, más directamente se comunica con el hardware de la máquina.
2.1. Bajo nivel: hablar directamente con la máquina
En los primeros ordenadores, los programadores tenían que escribir las instrucciones directamente en lenguaje máquina, es decir, en código binario (combinaciones de 0 y 1). Cada número representaba una operación concreta (sumar, comparar, mover datos…).
Por ejemplo, una instrucción como esta:
10110000 01100001
podía significar algo tan simple como «mueve el valor 97 al registro A».
Era un lenguaje muy rápido para el ordenador, pero muy difícil para el ser humano. Escribir programas complejos así era casi imposible, y cualquier error obligaba a empezar de nuevo.

Más adelante surgieron los lenguajes ensambladores, un poco más comprensibles, porque usaban abreviaturas llamadas mnemónicos (por ejemplo, MOV, ADD, JMP), pero seguían siendo muy dependientes del tipo de procesador.

Un programador en ensamblador tenía que preocuparse por detalles del hardware, como los registros, las direcciones de memoria o los saltos entre instrucciones.
Podemos decir que estos lenguajes están al nivel del ordenador, no de la persona.
2.2. Medio nivel: un paso hacia la comprensión
Con el tiempo, aparecieron lenguajes como C, que combinaban la potencia del bajo nivel con una sintaxis más cercana al razonamiento humano. En estos lenguajes todavía era necesario conocer cómo funcionaba el ordenador, pero ya permitían escribir programas mucho más complejos de manera estructurada.
Podríamos decir que los lenguajes de medio nivel son una especie de «puente» entre la máquina y el programador.
Por ejemplo, en C podríamos escribir:
#include <stdio.h>
int main() {
int num=0,suma=0;
do {
suma=suma+num;
printf("Dame un número: ");
scanf("%d",&num);
} while(num>=0);
printf("La suma es: %d",suma);
return 0;
}Este fragmento ya resulta legible, aunque sigue siendo bastante técnico.
2.3. Alto nivel: hablar en términos humanos
Finalmente, aparecieron los lenguajes de alto nivel, diseñados para que los programadores pudieran expresar sus ideas de una manera más natural, sin preocuparse por cómo el ordenador ejecuta cada paso internamente.
En un lenguaje de alto nivel como Java, mostrar la suma de dos números sería:
int a=5;
int b=3;
int suma=a+b;
System.out.println("La suma es "+suma);Aquí el código es casi autoexplicativo. No necesitamos saber qué registros utiliza el procesador ni cómo maneja la memoria. Simplemente expresamos lo que queremos hacer, y el compilador se encarga de traducirlo a lenguaje máquina.
Por eso, los lenguajes de alto nivel son los más utilizados hoy en día. Son más fáciles de aprender, más portables y mucho más productivos.
¿Compilador? ↓
2.4. Compiladores e intérpretes
A pesar de que escribimos el código en lenguajes de alto nivel, hemos dicho que los ordenadores sólo entienden lenguaje máquina. Entonces, ¿cómo es posible que entiendan algo como «System.out.println»?
La respuesta está en los compiladores e intérpretes, programas que actúan como traductores entre nuestro código y el procesador.
Java, por su parte, combina ambas ideas. Cuando escribimos un programa en Java, el compilador lo traduce primero a un lenguaje intermedio llamado «bytecode», que no depende del sistema operativo. Después, ese bytecode se ejecuta mediante la Máquina Virtual de Java (JVM), que actúa como intérprete.
Esto significa que un mismo programa Java puede ejecutarse en cualquier ordenador, ya sea Windows, macOS o Linux, sin tener que modificar el código.
Por eso se dice que Java es multiplataforma, y una de las razones por las que es tan utilizado en la industria.
3. Estructura básica de un programa
Sabemos que un lenguaje de programación es una forma estructurada de dar órdenes a un ordenador. Pero, igual que en cualquier idioma, esas órdenes deben seguir una gramática y una estructura concreta para que tengan sentido. En programación a esa gramática la llamamos sintaxis, y si no la respetamos, el ordenador simplemente no entenderá nuestras instrucciones.
Por tanto, antes de hacer cosas más complejas —como cálculos, decisiones o repeticiones— debemos comprender cómo se organiza un programa, qué elementos mínimos lo forman y cuál es su estructura general.
3.1. Estructura básica de un programa en Java
Todo programa en Java, por pequeño que sea, debe seguir una estructura común.
Podemos compararlo con la estructura de una redacción en lengua castellana: siempre hay que indicar la introducción, desarrollo y cierre.
En Java, esas partes son más formales, pero cumplen una función parecida.
Inicialmente, y mientras nos vamos haciendo con la sintaxis del lenguaje, usaremos este IDE online: MyCompiler.io »
Veamos el ejemplo clásico: el programa «Hola Mundo».
public class HolaMundo {
public static void main(String[] args) {
System.out.println("Hola mundo");
}
}A simple vista parece mucho texto para una frase tan corta, pero en realidad cada línea cumple una función muy concreta. Analicémoslo paso a paso.
3.2. Sintaxis y legibilidad
En Java, como en todos los lenguajes de programación, la forma importa tanto como el contenido.
Algunas normas esenciales que conviene respetar desde el principio son:
- Cada instrucción termina con un punto y coma (;).
- Las llaves { } se abren y cierran correctamente para delimitar bloques.
- El nombre de la clase comienza con mayúscula, y los de las variables y métodos con minúscula (convención camelCase).
- Los nombres deben ser descriptivos. Por ejemplo, notaAlumno es más claro que x.
- El código debe identarse (dejar sangrías que establecemos pulsando la tecla Tabulador) para que sea legible visualmente.
El objetivo es que otro programador pueda leer nuestro código y entenderlo fácilmente, igual que tú puedes entender un texto bien escrito aunque no lo hayas redactado tú.
3.3. Del texto al programa ejecutable
Cuando escribimos este código en nuestro entorno de desarrollo y pulsamos el botón «Ejecutar», el IDE realiza tres pasos invisibles pero fundamentales:
- Guarda el archivo con el nombre de la clase (HolaMundo.java).
- Compila el código, es decir, lo traduce a un formato que la máquina virtual de Java entiende (HolaMundo.class).
- Ejecuta ese archivo, mostrando el resultado en la consola de salida:
Hola mundo
Enhorabuena, has ejecutado tu primer programa: el ordenador ya te obedece.
4. Tipos básicos de datos
Hemos visto que un programa está formado por instrucciones que el ordenador ejecuta en un orden determinado. Pero, ¿qué es lo que manipula realmente un programa?
Datos.
Los datos son la materia prima de la programación: números, textos, caracteres, resultados de operaciones, respuestas de usuarios, estados de sensores, etc. Todo lo que un programa procesa o muestra es un dato.
En Java, cada dato pertenece a un tipo, y cada tipo determina qué clase de información puede almacenarse y qué operaciones pueden realizarse con ella.
Íntimamente relacionado con el tipo de dato, tenemos a las variables, auténticas protagonistas del código. Podemos entender que una variable es como una caja donde guardamos un valor (las veremos en profundidad más adelante). El tipo de dato define de qué tamaño y forma es esa caja y qué puede contener.
Por ejemplo:
- Una caja para guardar números enteros (int) puede contener valores como 3, -12 o 587.
- Una caja para guardar texto (String) puede contener palabras o frases como “Hola” o “Introduce un número con decimales”.
- Una caja para guardar valores lógicos (boolean) solo puede tener dos estados: true o false.
Si intentamos guardar un texto en una caja para números, el ordenador no sabrá qué hacer y lanzará un error. Por eso es tan importante indicar el tipo de cada dato.
Java define una serie de tipos primitivos, llamados así porque son los más básicos, los que no se pueden descomponer en otros. Estos son los más utilizados:
| Tipo | Significado | Ejemplo de valor | Tamaño aproximado |
| int | número entero | 7, -32, 1050 | 4 bytes |
| double | número decimal (coma flotante) | 3.14, -0.75 | 8 bytes |
| char | carácter individual | ‘A’, ‘3’, ‘?’ | 2 bytes |
| boolean | valor lógico | true, false | 1 bit |
Además, Java incluye otros tipos numéricos más específicos (byte, short, long, float), aunque en esta etapa usaremos sobre todo int y double.
Veamos algunos ejemplos sencillos para entender cómo se declaran y utilizan estos tipos en un programa Java.
Ejemplo 1: trabajar con números enteros y decimales.
public class TiposNumericos {
public static void main(String[] args) {
int edad = 17;
double notaMedia = 8.75;
System.out.println("Edad: " + edad);
System.out.println("Nota media: " + notaMedia);
}
}Aquí hemos declarado dos variables (edad y notaMedia), cada una de un tipo distinto, y las hemos mostrado por pantalla.
Ejemplo 2: trabajar con caracteres.
public class TipoChar {
public static void main(String[] args) {
char letraInicial = 'L';
char signo = '?';
System.out.println("Inicial del nombre: " + letraInicial);
System.out.println("Signo final: " + signo);
}
}El tipo char solo permite un carácter y se escribe entre comillas simples (‘ ‘), mientras que los textos completos usan comillas dobles (” “), como veremos más adelante.
Ejemplo 3: valores lógicos o booleanos.
public class TipoBooleano {
public static void main(String[] args) {
boolean mayorEdad = true;
boolean tieneCarnet = false;
System.out.println("¿Es mayor de edad? " + mayorEdad);
System.out.println("¿Tiene carnet de conducir? " + tieneCarnet);
}
}Los valores booleanos (true y false) son fundamentales para la toma de decisiones, algo que usaremos más adelante en las estructuras condicionales.
Aunque técnicamente String no es un tipo primitivo (es un objeto), en la práctica se comporta como uno de ellos y lo usaremos desde el principio. Permite almacenar textos completos.
public class TipoString {
public static void main(String[] args) {
String nombre = "Teresa";
String saludo = "Hola " + nombre + ", bienvenida al curso.";
System.out.println(saludo);
}
}El signo + sirve aquí para concatenar (unir) textos. Java tratará todos los valores que estén entre comillas dobles (” “) como cadenas de texto.
A veces un programa necesita combinar o convertir tipos de datos. Esto se llama conversión de tipos (casting).
Ejemplo: conversión de entero a decimal.
int numeroEntero = 5; double numeroDecimal = numeroEntero; // Conversión automática (de int a double) System.out.println(numeroDecimal);
Java puede convertir automáticamente un tipo más pequeño en otro más grande (por ejemplo, de int a double), pero si queremos hacer lo contrario, debemos indicarlo expresamente:
double nota = 8.7; int notaEntera = (int) nota; // Conversión forzada System.out.println(notaEntera);
El valor decimal se trunca (no se redondea), mostrando solo la parte entera.
En esta etapa inicial del aprendizaje de Java es normal cometer errores al mezclar tipos de datos. Por ejemplo, intentar hacer operaciones entre números y textos:
int edad = 17;
System.out.println("Edad + 1 = " + edad + 1);Este código no sumará 1 a la edad, sino que mostrará:
Edad + 1 = 171
¿Por qué? Porque el símbolo +, cuando intervienen cadenas de texto, actúa como concatenador. Para que realice la suma correctamente debemos usar paréntesis:
int edad = 17;
System.out.println("Edad + 1 = " + (edad + 1));Ahora sí mostrará:
Edad + 1 = 18
Es muy importante que analices las necesidades de cada problema y elijas los tipos de datos adecuados en cada momento para evitar errores inesperados cuando el programa crezca.
5. Variables y constantes
Como has podido comprobar, en nuestros programas necesitamos estar continuamente almacenando información: nombres, números, resultados de cálculos, respuestas del usuario, etc. Esa información debe poder guardarse temporalmente en la memoria del ordenador para poder utilizarla más adelante.
Para eso existen dos elementos obligatorios en cualquier lenguaje de programación: las variables y las constantes.
Ambas funcionan como «contenedores« o «cajas» donde guardamos datos, pero se comportan de manera distinta:
- Una variable puede cambiar su contenido durante la ejecución del programa.
- Una constante conserva siempre el mismo valor; no puede modificarse una vez asignada.
Podemos imaginar una variable como una caja con etiqueta. En la etiqueta escribimos su nombre, y dentro guardamos un valor. Más tarde podemos abrir la caja, cambiar lo que hay dentro y volver a cerrarla.
En Java, declarar una variable significa reservar un espacio en memoria e indicar qué tipo de dato guardará.
La forma general es:
tipo nombre = valorInicial;
Por ejemplo:
int edad = 16; double notaMedia = 8.5; String nombre = "Carlos"; boolean aprobado = true;
Cada una de estas líneas crea una variable distinta.
edad almacena un número entero.
notaMedia guarda un número con decimales.
nombre contiene un texto.
aprobado guarda un valor lógico (verdadero o falso).
Una vez declarada la variable, podemos usarla, modificarla o combinarla con otras.
Ejemplo:
public class Variables {
public static void main(String[] args) {
int edad = 16;
System.out.println("Edad inicial: " + edad);
edad = edad + 1; // La variable cambia
System.out.println("Edad después de un año: " + edad);
}
}A diferencia de las variables, una constante es un valor que no cambia durante la ejecución del programa. Se utiliza para representar datos fijos, como el número pi, el IVA o el número máximo de alumnos por clase.
En Java se declaran usando la palabra clave final.
final double PI = 3.14159; final int DIAS_SEMANA = 7; final double IVA = 0.21;
Si intentamos modificar una constante, el compilador mostrará un error:
final double PI = 3.14; PI = 4;

Veamos un ejemplo combinado:
public class CalculoArea {
public static void main(String[] args) {
final double PI = 3.1416; // Constante
double radio = 5; // Variable
double area = PI * radio * radio;
System.out.println("El área del círculo es: " + area);
// Si cambiamos el valor del radio, el resultado cambia
radio = 10;
area = PI * radio * radio;
System.out.println("El área del nuevo círculo es: " + area);
}
}Aquí el valor de PI nunca cambia, porque es una constante, pero el valor del radio sí, porque es una variable.
5.1. Salida de datos
Como ya sabemos, en todo programa informático distinguimos tres fases básicas:
- Entrada de datos (lo que el usuario proporciona).
- Procesamiento (lo que el programa hace con esos datos).
- Salida de datos (lo que el programa muestra como resultado).
La salida de datos es, por tanto, el medio por el cual un programa comunica información al usuario. En el caso más habitual —y el primero que aprendemos— esa comunicación se realiza a través de la pantalla, donde el programa muestra textos, resultados de cálculos o mensajes explicativos.
En Java, la salida de datos se realiza a través del flujo de salida estándar, representado por el objeto System.out.
Es una vía que el programa utiliza para enviar información hacia el exterior, normalmente hacia la consola o terminal.
La instrucción más utilizada es:
System.out.println("Mensaje a mostrar");System es una clase incluida en la biblioteca estándar de Java.
out es un objeto de esa clase que gestiona la salida de información.
println() es un método que imprime el texto y añade un salto de línea al final. Si no queremos que se haga un salto de línea al final, escribimos print() a secas.
Ejemplo:
System.out.println("Hola, usuario");
System.out.println("Bienvenido al programa de notas");
// Salida:
// Hola, usuario
// Bienvenido al programa de notasOtra forma muy común de mostrar información en pantalla es concatenar texto y variables con el operador +.
Ejemplo:
String nombre = "Carlos";
int edad = 17;
System.out.println("El alumno " + nombre + " tiene " + edad + " años.");
// Salida:
// El alumno Carlos tiene 17 años.En esta fase de tu aprendizaje, la pantalla es tu principal medio de comunicación con el programa. Cada vez que escribimos una línea como System.out.println(), el ordenador “responde” a nuestras instrucciones y nos permite comprobar si el programa funciona correctamente.
Por eso, dominar la salida de datos es fundamental para:
- Comprobar el funcionamiento del código.
- Depurar errores (mostrando valores intermedios de variables).
- Presentar resultados de forma clara y ordenada.
Cuando los programas crezcan, aprenderemos a enviar esa misma información no solo a la pantalla, sino también a archivos, bases de datos o interfaces gráficas, pero la lógica seguirá siendo la misma: mostrar de forma comprensible lo que el programa está haciendo.
5.2. Entrada de datos
Si la salida de datos nos permite que el programa se comunique con nosotros, la entrada de datos permite que nos comuniquemos con el programa.
En esta etapa de nuestro aprendizaje, la forma más habitual de recibir información es mediante el teclado, es decir, escribiendo datos en la consola. En Java, esta entrada se obtiene a través de un objeto muy utilizado: Scanner.
Para poder usarlo, debemos importar su clase al inicio del archivo, haciendo:
// importamos la clase import java.util.Scanner; // Creamos un objeto Scanner: Scanner sc = new Scanner(System.in);
System.in representa el flujo de entrada estándar, es decir, el teclado.
sc es el nombre del lector que vamos a utilizar.
Podemos imaginar que Scanner es como un “micrófono” del programa: “escucha” lo que el usuario escribe y lo convierte en el tipo de dato adecuado.
Scanner dispone de métodos para leer distintos tipos de valores.
Los más importantes para empezar son:
- nextInt(): lee un tipo entero (int), como la edad.
- nextDouble(): lee un tipo decimal (double), como la nota media.
- nextBoolean(): lee un tipo lógico (boolean), como true o false.
- nextLine(): lee un texto completo, como un nombre con apellidos.
- next(): lee una una palabra (hasta el primer carácter espacio), como un día de la semana.
Por ejemplo:
// importamos la clase
import java.util.Scanner;
// abrimos un canal de lectura
Scanner sc = new Scanner(System.in);
// informamos al usuario de lo que necesitamos
System.out.print("Introduce tu edad: ");
// leemos de teclado
int edad = sc.nextInt();
// mostramos el resultado
System.out.println("Tienes " + edad + " años.");
// cerramos el canal de lectura
sc.close();
// Salida:
// Introduce tu edad: 16
// Tienes 16 años.Un fallo muy común ocurre cuando mezclamos nextInt() o nextDouble() con nextLine().
Estos métodos no consumen el salto de línea que el usuario introduce al pulsar Enter, lo que provoca que el siguiente nextLine() lea una línea vacía.
Ejemplo del error:
System.out.print("Edad: ");
int edad = sc.nextInt();
System.out.print("Nombre: ");
String nombre = sc.nextLine(); // <-- lee una línea vacía
// Solución: añadir un nextLine() “extra” para limpiar el buffer:
System.out.print("Edad: ");
int edad = sc.nextInt();
sc.nextLine(); // limpia el salto de línea pendiente
System.out.print("Nombre: ");
String nombre = sc.nextLine();Esto evita comportamientos extraños y hace que el programa sea robusto.
En aplicaciones reales, no podemos confiar en que el usuario escriba siempre valores válidos. Por eso es habitual combinar la entrada con bucles.
Ejemplo: pedir una nota entre 0 y 10
double nota;
do {
System.out.print("Introduce una nota válida (0-10): ");
nota = sc.nextDouble();
} while (nota < 0 || nota > 10);
System.out.println("Nota aceptada: " + nota);Este patrón es muy útil para evitar errores de ejecución.
6. Operadores y expresiones
Un programa no se limita a guardar datos: necesita manipularlos, compararlos y combinarlos para obtener resultados nuevos.
Para ello utilizamos los operadores, que son símbolos especiales que indican qué tipo de operación queremos realizar. Al combinar operadores y datos formamos expresiones, que son la base de todas las instrucciones en un lenguaje de programación.
6.1. Operadores aritméticos
Son los que se utilizan para realizar cálculos matemáticos. Funcionan igual que en la vida real, pero con la sintaxis de Java.
| Operador | Significado | Ejemplo | Resultado |
| + | Suma | 5 + 3 | 8 |
| – | Resta | 10 – 4 | 6 |
| * | Multiplicación | 6 * 2 | 12 |
| / | División | 10 / 2 | 5 |
| % | Resto (módulo) | 10 % 3 | 1 |
Ejemplo:
public class OperadoresAritmeticos {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println("Suma: " + (a + b));
System.out.println("Resta: " + (a - b));
System.out.println("Multiplicación: " + (a * b));
System.out.println("División: " + (a / b));
System.out.println("Resto: " + (a % b));
}
}6.2. Operadores de asignación
Ya conocemos el operador =, que sirve para asignar un valor a una variable. Pero también existen versiones abreviadas que combinan asignación con una operación, aunque nosotros no los veremos para no aumentar innecesariamente la cantidad de instrucciones que debes dominar, ya que no aportan nada especial.
6.3. Operadores de comparación
Sirven para comparar valores y devuelven un resultado lógico (true o false). Son fundamentales en las estructuras condicionales, que veremos más adelante.
| Operador | Significado | Ejemplo | Resultado |
| == | Igual que | 5 == 5 | true |
| != | Distinto de | 5 != 3 | true |
| > | Mayor que | 8 > 2 | true |
| < | Menor que | 3 < 1 | false |
| >= | Mayor o igual que | 4 >= 4 | true |
| <= | Menor o igual que | 2 <= 5 | true |
Ejemplo:
public class OperadoresComparacion {
public static void main(String[] args) {
int nota = 7;
System.out.println(nota >= 5); // true
System.out.println(nota == 10); // false
System.out.println(nota != 4); // true
}
}6.4. Operadores lógicos
Nos permiten combinar condiciones. Por ejemplo, podemos preguntar si un alumno ha aprobado y además tiene la asistencia suficiente.
| Operador | Significado | Ejemplo | Resultado |
| && | Y lógico (AND) | (nota >= 5 && asistencia >= 80) | true si ambas son verdaderas |
| || | O lógico (OR) | (nota >= 5 || asistencia >= 80) | true si alguna de ellas es verdadera |
| ! | No lógico (NOT) | !(nota >= 5) | Invierte el valor: false si era true |
Ejemplo:
public class OperadoresLogicos {
public static void main(String[] args) {
int nota = 6;
int asistencia = 85;
boolean comportamiento = true;
boolean aprobado = (nota >= 5 && asistencia >= 80 && comportamiento);
System.out.println("¿El alumno aprueba? " + aprobado);
}
}¿El alumno aprueba?
6.5. Precedencia de operadores
Cuando escribimos expresiones con varios operadores, no todos se ejecutan en el mismo orden. Java sigue unas reglas llamadas precedencia de operadores, parecidas a las matemáticas, es decir, qué operaciones tienen prioridad sobre las demás.
Por ejemplo:
int resultado = 3 + 2 * 5;
El resultado es 13, no 25, porque la multiplicación se realiza antes que la suma.
Si queremos alterar el orden, usamos paréntesis:
int resultado = (3 + 2) * 5; // ahora es 25
Esta es la relación completa ordenada por prioridad de los operadores de Java:
- Paréntesis: los operadores dentro de paréntesis se evalúan primero.
- Operadores unarios: pperadores como incremento (++) y decremento (–), así como el signo negativo (-).
- Operadores de multiplicación, división y módulo: *, /, %.
- Operadores de suma y resta: +, -.
- Operadores de desplazamiento de bits: <<, >>, >>>.
- Operadores relacionales: <, <=, >, >=.
- Operadores de comparación: ==, !=.
- Operadores lógicos AND: &, &&.
- Operadores lógicos XOR: ^.
- Operadores lógicos OR: |, ||.
- Operador condicional: ?:.
- Operadores de asignación: =, +=, -=, etc.
Evidentemente hay más de los que conoces, pero no está mal que te suenen.
Veamos, para terminar este apartado, un par de ejemplos que nos ayuden a practicar un poco más escribiendo código.
Ejemplo: calcular la nota final de un alumno.
public class NotaFinal {
public static void main(String[] args) {
double examen = 7.5;
double trabajo = 8;
double actitud = 9;
double notaFinal = (examen * 0.6) + (trabajo * 0.3) + (actitud * 0.1);
System.out.println("La nota final es: " + notaFinal);
}
}Ejemplo: comprobar si un número es par.
int numero = 12;
boolean esPar = (numero % 2 == 0);
System.out.println("¿El número es par? " + esPar);7. Comentarios
Hemos aprendido a escribir programas que hacen cálculos, muestran resultados y almacenan datos. Pero hay algo igual de importante que hacer que el programa funcione: hacer que se entienda.
Para eso existen los comentarios, una herramienta que permite escribir notas explicativas dentro del código sin que el ordenador las ejecute.
El objetivo es explicar qué hace una instrucción, por qué se ha escrito de una determinada forma o qué parte del programa falta por completar.
El compilador de Java ignora los comentarios, es decir, los salta como si no existieran. Su único propósito es ayudar a los seres humanos a entender el código.
7.1. Tipos de comentarios en Java
Java permite tres tipos de comentarios, según su extensión y uso.
- Comentario de una sola línea
Se escribe con doble barra inclinada (//). Todo lo que esté a la derecha de // se considera comentario.
public class ComentarioSimple {
public static void main(String[] args) {
// Este programa muestra un saludo por pantalla
System.out.println("Hola, mundo"); // Mensaje principal
}
}- Comentario de varias líneas
Se utiliza cuando queremos escribir una explicación más larga. Empieza con /* y termina con */.
public class ComentarioMultiple {
public static void main(String[] args) {
/*
Este programa calcula la suma de dos números.
Fue creado por el grupo de 2º de Bachillerato.
*/
int a = 5;
int b = 7;
System.out.println("La suma es " + (a + b));
}
}- Comentario de documentación
Se usa para documentar clases, métodos o variables, especialmente cuando el código va a ser compartido o publicado. Empieza con /** y termina con */.
Los entornos de desarrollo pueden leer estos comentarios y generar documentación automática.
/**
* Clase que realiza cálculos relacionados con un círculo.
* Autor: Lope González Vázquez
* Fecha: 5 de octubre de 2025
*/
public class Circulo {
/**
* Calcula el área de un círculo a partir del radio.
* @param radio radio del círculo
* @return área del círculo
*/
public static double area(double radio) {
final double PI = 3.1416;
return PI * radio * radio;
}
}7.2. El equilibrio justo
Aunque los comentarios son fundamentales, no deben usarse en exceso.
Comentar cada línea puede hacer que el código sea más difícil de leer. Lo ideal es que el propio código sea lo bastante claro, y los comentarios sirvan solo para explicar lo que no se ve directamente.
❌ Un mal ejemplo sería esto:
int a = 5; // Declaro variable a int b = 3; // Declaro variable b int suma = a + b; // Sumo a y b
Estos comentarios no aportan nada nuevo.
✅ En cambio, sí merece la pena comentar una parte del código que pueda resultar confusa o tener una justificación concreta:
// Multiplicamos por 100 para evitar errores de redondeo double precioFinal = precioBase * 1.21 * 100;
8. Estructuras de control condicionales
Nuestros programas han seguido hasta ahora un orden lineal: se ejecutan las instrucciones una tras otra, de arriba abajo, sin posibilidad de elección.
Sin embargo, la mayoría de los programas que usamos cada día no funcionan así: toman decisiones.
Por ejemplo, un videojuego decide si el jugador gana o pierde según su puntuación; una aplicación bancaria aprueba o rechaza una transferencia según el saldo disponible; un programa escolar muestra «Aprobado» o «Suspenso» según la nota.
Para que un programa pueda tomar decisiones, necesitamos introducir una estructura que permita elegir entre varios caminos posibles según una condición. En Java, esa estructura se llama estructura condicional.
8.1. El concepto de condición
Una condición es una expresión que el programa puede evaluar como verdadera (true) o falsa (false).
Por ejemplo:
edad >= 18 // → ¿Es mayor o igual que 18?
nota < 5 // → ¿Es menor que 5?
usuario.equals("admin") // → ¿El nombre introducido es “admin”?Si la condición se cumple (es verdadera), el programa ejecuta un bloque de instrucciones; si no, puede ejecutar otro bloque alternativo.
8.2. La estructura if
La estructura más sencilla para tomar decisiones es el if (del inglés if = si).
Su sintaxis básica es:
if (condición) {
// instrucciones si la condición es verdadera
}Ejemplo:
int edad = 20;
if (edad >= 18) {
System.out.println("Eres mayor de edad");
}
// Salida: Eres mayor de edad Si cambiamos edad a 16, el programa no mostrará nada, porque la condición no se cumple.
8.3. La estructura if-else
A veces queremos que el programa haga una cosa si la condición es verdadera y otra diferente si es falsa.
En ese caso usamos if-else:
if (condición) {
// bloque si la condición es verdadera
} else {
// bloque si la condición es falsa
}Ejemplo:
int nota = 7;
if (nota >= 5) {
System.out.println("Aprobado");
} else {
System.out.println("Suspenso");
}
// Salida: Aprobado8.4. Condicionales encadenados
Si hay más de dos opciones posibles, podemos encadenar varios if seguidos.
if (condición1) {
// si se cumple la primera
} else if (condición2) {
// si no se cumple la primera pero sí esta segunda
} else {
// si no se cumple ninguna de las anteriores
}Ejercicio resuelto
Escribe un programa que dada una calificación numérica entera de 0 a 10 devuelva la calificación en formato: Suspenso, Aprobado, Notable o Sobresaliente.
int nota = 8;
if (nota < 5) {
System.out.println("Suspenso");
} else if (nota < 7) {
System.out.println("Aprobado");
} else if (nota < 9) {
System.out.println("Notable");
} else {
System.out.println("Sobresaliente");
}8.5. El operador ternario
Java también ofrece una forma más compacta de escribir condiciones sencillas, llamada operador ternario.
Su sintaxis es:
resultado = (condición) ? valor_si_true : valor_si_false;
Ejemplo:
int edad = 17; String mensaje = (edad >= 18) ? "Mayor de edad" : "Menor de edad"; System.out.println(mensaje); // Salida: Menor de edad
Este operador se usa mucho para expresiones cortas, aunque se desaconseja en decisiones largas o con muchos casos, porque puede dificultar la lectura del código.
8.6. Anidamiento de condicionales
Llamamos anidamiento a incluir un if dentro de otro.
Ejemplo: control de acceso a una sala.
int edad = 19;
boolean tieneEntrada = true;
if (edad >= 18) {
if (tieneEntrada) {
System.out.println("Puedes entrar a la sala");
} else {
System.out.println("Necesitas una entrada para entrar");
}
} else {
System.out.println("No tienes la edad mínima");
}El programa primero comprueba la edad y, solo si es suficiente, comprueba si tiene entrada.
Ejercicio resuelto
Escribe un programa que dada una edad aplique un descuento del 20% a los menores de edad y a los estudiantes, y un descuento del 30% a los jubilados.
public class Descuentos {
public static void main(String[] args) {
int edad = 17;
boolean estudiante = true;
double descuento;
if (edad < 18 || estudiante) {
descuento = 0.20;
} else if (edad >= 65) {
descuento = 0.30;
} else {
descuento = 0.0
}
System.out.println("Descuento aplicado: " + (descuento * 100) + "%");
}
}Aquí vemos cómo se combinan condiciones con el operador lógico || (o), para ofrecer descuentos según la edad o la condición de estudiante.
9. Estructuras de control iterativas
En muchos casos no basta con decidir entre un camino u otro, sino que el programa necesita repetir una acción varias veces.
Por ejemplo, imagina que queremos mostrar en pantalla los números del 1 al 100, o calcular la media de 20 notas. Podríamos escribir una instrucción System.out.println para cada número, pero eso sería absurdo y muy poco práctico.
Para estos casos usamos las estructuras de control iterativas, también llamadas bucles, que permiten repetir un bloque de instrucciones de forma automática, tantas veces como sea necesario.
9.1. Concepto de iteración
Iterar significa repetir una acción un número determinado de veces o hasta que se cumpla una condición.
Cada repetición se llama una iteración del bucle, y dentro de él puede haber instrucciones que cambien variables, acumulen resultados o generen salidas por pantalla: el programa entra, ejecuta un conjunto de órdenes, y cuando termina, vuelve al principio para comprobar si debe seguir o parar.
9.2. El bucle while
El bucle while repite las instrucciones mientras se cumpla una condición.
Su estructura es la siguiente:
while (condición) {
// bloque de instrucciones
}Ejercicio resuelto
Escribe un programa que cuente del 1 al 5.
int contador = 1;
while (contador <= 5) {
System.out.println("Número: " + contador);
contador++;
}El bucle comienza con contador = 1 y sigue ejecutándose mientras contador <= 5 sea verdadero. En cada vuelta, se incrementa contador con contador++.
9.3. El bucle do…while
El bucle do…while es muy parecido al anterior, pero con una diferencia importante: siempre se ejecuta al menos una vez, porque la condición se comprueba después del bloque.
do {
// instrucciones
} while (condición);Ejercicio resuelto
Escribe un programa que pida por teclado una nota de 0 a 10 hasta que sea correcta.
import java.util.Scanner;
public class NotaValida {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double nota;
do {
System.out.print("Introduce una nota entre 0 y 10: ");
nota = sc.nextDouble();
} while (nota < 0 || nota > 10);
System.out.println("Nota registrada: " + nota);
sc.close();
}
}El bucle se repite mientras la nota sea menor que 0 o mayor que 10, asegurando que el valor introducido sea correcto.
9.4. El bucle for
El bucle for se usa cuando sabemos de antemano cuántas veces queremos repetir algo.
Su estructura reúne en una sola línea la inicialización, la condición y el incremento.
for (inicio; condición; actualización) {
// bloque de instrucciones
}Ejercicio resuelto
Escribe un programa que muestre los números del 1 al 10.
for (int i = 1; i <= 10; i++) {
System.out.println("Número: " + i);
}El bucle comienza con i = 1, repite mientras i <= 10, y en cada iteración aumenta i en 1 (i++).
Ejercicio resuelto
Escribe un programa que muestre la tabla de multiplicar del 7.
int numero = 7;
for (int i = 1; i <= 10; i++) {
System.out.println(numero + " x " + i + " = " + (numero * i));
}9.5. Bucles anidados
Un bucle anidado es un bucle dentro de otro.
Se utiliza, por ejemplo, para mostrar una tabla de multiplicar completa:
for (int i = 1; i <= 10; i++) {
System.out.println("Tabla del " + i + ":");
for (int j = 1; j <= 10; j++) {
System.out.println(i + " x " + j + " = " + (i * j));
}
System.out.println(); // línea en blanco
}Cada vez que se ejecuta el bucle externo (i), el interno (j) recorre de nuevo del 1 al 10.
9.6. Interrupción y continuación de bucles
Java ofrece dos instrucciones especiales para controlar el flujo de los bucles:
- break: sale del bucle inmediatamente, aunque la condición no se haya cumplido.
- continue: salta a la siguiente iteración, sin ejecutar el resto del bloque actual.
for (int i = 1; i <= 10; i++) {
if (i == 5) {
continue; // salta el número 5
}
if (i == 8) {
break; // se detiene completamente
}
System.out.println("Número: " + i);
}10. Estructuras de datos
En los epígrafes anteriores hemos trabajado con variables individuales: una para la edad, otra para la nota, otra para el nombre… Sin embargo, los programas del mundo real rara vez manejan un solo valor.
Imagina que queremos almacenar las notas de todos los alumnos de una clase. Podríamos declarar 30 variables diferentes (nota1, nota2, nota3, etc.), pero eso sería incómodo, repetitivo y difícil de mantener.
Aquí es donde entran en juego las estructuras de datos, que nos permiten almacenar y organizar varios valores relacionados bajo un mismo nombre.
Sirve para agrupar valores del mismo tipo (por ejemplo, las notas de una clase, los precios de un catálogo o las puntuaciones de un videojuego).
En Java existen numerosas estructuras de datos de enorme utilidad. Dos de las más utilizadas son los arrays (por su simplicidad) y un tipo especial de estructuras llamadas colecciones dinámicas, cuyo exponente más popular son los ArrayList.
10.1. Los arrays
Un array (también llamado vector) es una colección de elementos del mismo tipo.
Tiene un tamaño fijo, es decir, una vez creado no puede cambiar su longitud.
La sintaxis básica es:
tipo[] nombre = new tipo[tamaño];
Por ejemplo, si queremos guardar las notas de 5 alumnos:
double[] notas = new double[5];
Esto crea un array de 5 posiciones (de la 0 a la 4).
Podemos asignar valores de esta forma:
notas[0] = 7.5; notas[1] = 8.0; notas[2] = 6.5; notas[3] = 9.0; notas[4] = 7.0;
Y acceder a ellos:
System.out.println("Primera nota: " + notas[0]);
System.out.println("Última nota: " + notas[4]);10.2. Recorrer un array con un bucle
Normalmente, no escribimos cada posición a mano. Usamos un bucle para recorrer el array completo.
Ejemplo: mostrar todas las notas.
for (int i = 0; i < notas.length; i++) {
System.out.println("Nota " + (i + 1) + ": " + notas[i]);
}El atributo length indica el tamaño del array, y como los índices empiezan en 0, el último elemento está en la posición length – 1.
10.3. Inicialización directa
Podemos crear un array con sus valores ya asignados:
int[] edades = {16, 17, 16, 18, 17};Esto ahorra código y facilita la lectura.
Ejercicio resuelto
Escribe un programa que calcule la nota media de un array de notas.
public class MediaNotas {
public static void main(String[] args) {
double[] notas = {7.5, 8.0, 6.5, 9.0, 7.0};
double suma = 0;
for (int i = 0; i < notas.length; i++) {
suma += notas[i];
}
double media = suma / notas.length;
System.out.println("La nota media es: " + media);
}
}10.4. Bucle for-each
Java incluye una forma más sencilla de recorrer los arrays: el bucle for-each, que no requiere índices.
for (double nota : notas) {
System.out.println(nota);
}Esta estructura se lee así: para cada nota en el array notas…
Es ideal cuando solo queremos leer los valores sin modificar su posición.
10.5. El tipo ArrayList: listas dinámicas
Los arrays son útiles, pero tienen una limitación: no pueden cambiar de tamaño 💩.
Si necesitamos una colección que pueda crecer o reducirse, usamos un ArrayList, una estructura dinámica de la biblioteca de Java.
Su sintaxis básica es:
ArrayList<tipo> nombre = new ArrayList<tipo>();
Por ejemplo:
ArrayList<String> alumnos = new ArrayList<String>();
10.6. Operaciones básicas con ArrayList
Podemos añadir, acceder, modificar y eliminar elementos fácilmente.
Ejemplo: manipular una lista de alumnos.
import java.util.ArrayList;
public class ListaAlumnos {
public static void main(String[] args) {
ArrayList<String> alumnos = new ArrayList<String>();
alumnos.add("Lucía");
alumnos.add("Raúl");
alumnos.add("Teresa");
alumnos.add("Sergio");
System.out.println("Número de alumnos: " + alumnos.size());
System.out.println("Primer alumno: " + alumnos.get(0));
alumnos.set(2, "Teresa G."); // modificar
alumnos.remove(1); // eliminar
System.out.println("Lista final: " + alumnos);
}
}10.7. Recorrer un ArrayList
Podemos recorrerlo igual que un array, con un bucle for o for-each.
Ejemplo:
// Recorrer el ArrayList y mostrar su conenido
for (String alumno : alumnos) {
System.out.println("Alumno: " + alumno);
}
// Calcular cuántos nombres empiezan por T
int contador = 0;
for (String alumno : alumnos) {
if (alumno.startsWith("T")) {
contador++;
}
}
System.out.println("Alumnos cuyo nombre empieza por T: " + contador);En la práctica, los ArrayList se usan mucho más que los arrays, sobre todo cuando no conocemos de antemano el número de elementos que tendrá la lista.
Ejercicio resuelto
Escribe un programa que te permita introducir por teclado un número indeterminado de notas, calcule la nota media y la muestre en pantalla.
import java.util.ArrayList;
import java.util.Scanner;
public class GestionNotas {
public static void main(String[] args) {
ArrayList<Double> notas = new ArrayList<Double>();
Scanner sc = new Scanner(System.in);
double nota;
System.out.println("Introduce las notas (número negativo para terminar):");
do {
nota = sc.nextDouble();
if (nota >= 0) {
notas.add(nota);
}
} while (nota >= 0);
double suma = 0;
for (double n : notas) {
suma += n;
}
double media = suma / notas.size();
System.out.println("La nota media del grupo es: " + media);
sc.close();
}
}11. Funciones
En los programas que hemos escrito hasta ahora, todas las instrucciones estaban dentro del método principal main. Eso funciona bien cuando el programa es pequeño, pero si crece, el código se vuelve largo, repetitivo y difícil de mantener.
Además, a veces necesitamos que en varios puntos del programa se ejecuten las mismas 10, 20 o 30 líneas de código. ¿Tendrías que copiar y pegar las mismas líneas cada vez?
No.
La solución es encapsular ese conjunto de instrucciones en una función, para poder reutilizarlo todas las veces que haga falta.
Una función (en Java se llama método) es un bloque de código que realiza una tarea concreta y que puede invocarse (llamarse) desde cualquier parte del programa.
Puedes imaginarlos como un mini programa que hace una tarea concreta.
Por ejemplo:
- Si le das una temperatura en grados Celsius, puede devolverte su valor en Fahrenheit.
- Si le das dos números, puede devolverte su suma.
- Si le das una lista de notas, puede devolverte la media.
Las ventajas son, por tanto:
- Reutilización: escribimos una vez y usamos muchas.
- Organización: el código se divide en bloques con sentido.
- Legibilidad: el programa se entiende mejor porque cada parte tiene un nombre descriptivo.
- Depuración: los errores son más fáciles de localizar.
En definitiva, las funciones hacen que nuestro código sea más limpio, profesional y mantenible.
11.1. Estructura de una función
La forma general de declarar una función en Java es:
modificador tipoDevuelto nombre(parámetros) {
// instrucciones
return valor;
}Veamos qué significa cada parte:
🔵modificador: normalmente public o private, indica desde dónde se puede usar la función.
🔵tipoDevuelto: el tipo de dato que devuelve la función (int, double, String, etc.). Si no devuelve nada, se escribe void.
🔵nombre: el identificador del método (por convención, empieza en minúscula).
🔵parámetros: los valores que recibe para trabajar.
🔵return: la instrucción que devuelve el resultado.
Ahora a través de distintos ejemplos vamos a repasar los tipos de funciones más utilizados.
Una función puede simplemente ejecutar una acción sin necesitar datos ni devolver nada.
public static void mostrarSaludo() {
System.out.println("¡Bienvenido al curso de Programación y Computación!");
}Para ejecutarla desde main:
public static void main(String[] args) {
mostrarSaludo();
}Podemos pasarle datos a una función para que trabaje con ellos (darle valor a los parámetros).
public static void saludarPersona(String nombre) {
System.out.println("Hola, " + nombre + "!");
}Y la usamos así:
saludarPersona("Teresa");
// Salida: Hola, Teresa!
saludarPersona("Raúl");
// Salida: Hola, Raúl!Aquí el parámetro nombre actúa como una variable local que solo existe dentro de la función.
Una función puede devolver un resultado mediante la instrucción return.
public static int sumar(int a, int b) {
int resultado = a + b;
return resultado;
}Se llama así:
int suma = sumar(4, 7);
System.out.println("La suma es: " + suma);
// Salida: La suma es: 11Las funciones también pueden devolver valores lógicos, muy útiles en condiciones.
public static boolean esPar(int numero) {
return numero % 2 == 0;
}Y en el main:
if (esPar(6)) {
System.out.println("El número es par");
} else {
System.out.println("El número es impar");
}Veamos una función un poco más completa.
Ejercicio resuelto
Escribe una función que devuelva la media de tres notas que se le pasan como parámetro.
// Definición de la función
public static double calcularMedia(double n1, double n2, double n3) {
double suma = n1 + n2 + n3;
double media = suma / 3;
return media;
}
// Uso de la función
double media = calcularMedia(7.5, 8.0, 9.0);
System.out.println("La nota media es: " + media);
// Salida: La nota media es: 8.16666666666666611.2. Paso de parámetros
Cuando llamamos a una función, los valores que enviamos (llamados argumentos) se copian en las variables que la función declara (llamadas parámetros).
Esto significa que las variables dentro de la función no afectan a las del programa principal.
Ejemplo:
public static void duplicar(int numero) {
numero = numero * 2;
System.out.println("Dentro de la función: " + numero);
}
public static void main(String[] args) {
int x = 5;
duplicar(x);
System.out.println("Fuera de la función: " + x);
}
// Salida:
// Dentro de la función: 10
// Fuera de la función: 5El valor de x no cambia fuera de la función, porque Java pasa los valores por copia.
11.3. Reutilización y modularidad
Cuando un programa crece, se divide en métodos y en clases diferentes.
Cada uno se encarga de una parte concreta del trabajo, y todos colaboran para lograr el resultado final.
Así es como trabajan los equipos de desarrollo profesional: cada programador diseña y prueba sus propias funciones, que después se integran en un proyecto común.
Veamos un ejemplo que combina varias funciones:
public class GestionCalificaciones {
public static double calcularMedia(double n1, double n2, double n3) {
return (n1 + n2 + n3) / 3;
}
public static String obtenerResultado(double media) {
if (media >= 9)
return "Sobresaliente";
else if (media >= 7)
return "Notable";
else if (media >= 5)
return "Aprobado";
else
return "Suspenso";
}
public static void mostrarInforme(String alumno, double media, String resultado) {
System.out.println(alumno + " - Media: " + media + " - " + resultado);
}
public static void main(String[] args) {
String alumno = "Teresa";
double media = calcularMedia(8.5, 9.0, 7.5);
String resultado = obtenerResultado(media);
mostrarInforme(alumno, media, resultado);
}
}
// Salida:
// Teresa - Media: 8.333333333333334 - NotableAquí el programa está dividido en tres funciones claras: una calcula, otra evalúa y otra muestra. Cada una tiene un propósito concreto, y juntas forman un sistema completo, limpio y fácil de entender.