Pequeña guía para usar Java, nivel Algoritmos (parte 1)
Ésta pequeña guía1 está pensada no para ser un curso de Java ni nada por el estilo, sino que es para dar a conocer cómo usar lo básico de Java para poder resolver las tareas de Algoritmos mientras siga siendo el lenguaje oficial del curso. La segunda parte aún no está terminada, pero la puedes encontrar aquí.
<preámbulo>
Algo de historia: antiguamente, el curso de Algoritmos también era un curso para profundizar Java (recordar que Computación I, el antiguo Intro a la Progra, se dictaba en Java), por lo que cosas más técnicas sobre el lenguaje era posible evaluarlas. Ahora para Java está el CC3002 de Bergel, y el mito dice que posiblemente Algoritmos migre a Python en el futuro, pero eso está por verse.
</preámbulo>
0. Instalar Java
No es necesario que tengas ningún sistema operativo en particular instalado: la magia de Java es que los programas corren en una máquina virtual, de la misma manera siempre. Voy a suponer que no vas a usar ningún IDE, así que vas a necesitar una terminal (Símbolo del Sistema de Windows, ttyN
o emulador de terminal de *nix, lo que sea que traiga Mac) en el que puedas correr los comandos java
y javac
.
Para ver si tienes java
, haz:
java -version
Adivina qué tienes que hacer para ver si tienes javac
🙄:
javac -version
Si te sale algo la versión de Java, la palabra “runtime” o simplemente “javac 1.8…”, sáltate el resto de la sección. Si te sale algo como -bash: java: orden no encontrada
, sigue leyendo.
Ok, seguiste leyendo, así que probablemente no tienes java
/javac
instalado. Voy a decirte como instalarlos en Linux. Si tienes Windows, probablemente en la primera auxiliar tu auxiliar dijo cómo instalarlo, o dejó un post en el foro. Si no fuiste a la primera auxiliar, pues no es culpa mía, yo no soy tu auxiliar.
Para instalar javac
(viene con java
incluido) en (K,L,X)Ubuntu, haz:
sudo apt install default-jdk
(Si quieres el oficial de Oracle™, el repositorio es oracle-java8-installer
(o 7, dependiendo de la versión), pero con la versión abierta estás bien).
Para instalarlo en Arch, el comando es
sudo pacman -S jdk7-openjdk
Puedes escoger instalar la versión 7, 8, hasta la 10 cambiando el numerito: en el curso no va a importar. Puede que hayas escuchado que tal versión tiene algo genial… no te sirve de nada: vas a tener que implementar a mano hasta tus funciones2 para mover arreglos.
Ahora deberías tener instalado el JRE (Java Runtime Environment, más conocido como el programita java
que te deja correr otros programitas), y el JDK (Java Development Kit, más conocido como el programita javac
que compila -por eso la c- tus archivos .java en archivos que entiende la máquina de Java).
1. Hola mundo!
Vamos a escribir el programa de prueba más simple, para que te familiarices con las costumbres/mañas de Java. En un editor de texto, escribe el siguiente código (siempre es recomendable escribirlo a mano en vez de copypastear, para recordar las cosas por memoria muscular):
public class Hola {
public static void main(String[] args) {
System.out.println("Hola mundo!");
}
}
En la carpeta en que quieras, es importante que lo guardes con el nombre Hola.java
. Esto es porque la clase tiene que tener el mismo nombre del archivo (más detalle adelante). Ahora, para correrlo, puedes hacer:
javac Hola.java
java Hola
El primer comando generó un archivo llamado Hola.class
, el cual luego es el que corre el comando java
. Es un error muy común al arreglar un problema en el código no compilar de nuevo antes de correrlo. Puedes perder horas intentando arreglar errores que no existen. Siempre compila después de cualquier cambio.
2. public static qué? Me lo tengo que aprender?
Respuesta simple: No necesariamente.
Si vas a escribir Java desde un editor de textos simple, siempre puedes copiar el código de tu tarea anterior y modificar lo que necesites. De todas formas, si te hacen programar en Java en el control, no te van a descontar puntos por no poner los public: Algoritmos es un curso de algoritmos, no de Java.
Cuando tienes un archivo NombrePrograma.java
, lo compilas y luego lo corres, la máquina de Java lo primero que hace es buscar dentro de tu archivo una clase llamada NombrePrograma (no tiene por qué ser public). Luego, dentro de esa clase, busca una función2 que empiece exactamente con
public static void main(String[] args) {
...
}
Intenta cambiarle el nombre a la función, o quitarle el public, o ponerle un argumento extra. Lo único que te deja hacer es cambiar el nombre de la variable args
por otro.
Ahora bien, puedes tener más de una función, y en distintas clases… pero siempre va a ser uno el programa principal, ¿no?. Lo otro: si el archivo se llama NombrePrograma.java
, sólo la clase NombrePrograma puede ser public, si creas una clase Otra Clase que también sea public, Java te va a retar por no dejar esta otra clase en un archivo llamado OtraClase.java
.
En general es buena práctica en Java dejar todas las clases en archivos distintos. En general es buena práctica en las tareas de Algoritmos dejar todas las clases en el mismo archivo. Trust me, he corregido tareas de Algoritmos.
2.1. Entonces… qué significa el public?
Para eso está tooooodo el curso CC3002 Metodologías de Diseño y Programación
2.2. y el static?
Ah, sí, eso es importante3 (al menos útil) aquí. Más adelante lo veremos.
3. Ejemplos de Java
Como regla general, si vas a implementar Algoritmos, basta escribir todo dentro de la misma clase. Si vas a implementar Estructuras de Datos, posiblemente te ayude tener clases separadas.
Una de las cosas más simples y que probablemente más tengas que hacer en Algoritmos es usar, crear y recorrer arreglos, generalmente de números enteros. Si ya sabes C, C++ o algún otro hijo de C, probablemente ya tienes una idea de cómo se crean y utilizan variables, pero Java tiene más burocracia.
3.1. Primer intento
Si creamos un archivo con el contenido:
class Main {
public static void main(String[] args) {
System.out.println("Voy a crear un número");
int num = 7;
System.out.println("Número: "+num);
System.out.println();
String s = "Hola, voy a crear un arreglo";
System.out.println("Largo string: "+s.length());
System.out.println("Contenido string: '"+s+"'");
System.out.println();
int arr[] = new int[] {4, 6, 2, num, 281, 42};
System.out.println("Largo arreglo: "+arr.length);
System.out.println("Contenido arreglo: '"+arr+"'");
}
}
Obviamente el archivo anterior se tiene que llamar Main.java
. Probablemente ya te diste cuenta que el System.out.println
es una especie de print; bueno, es más que eso: Java tiene más de un print:
System.out.print
imprime lo que le pases en pantalla.System.out.println
hace lo mismo que elSystem.out.print
, pero agrega un salto de línea al final.System.out.println(string)
es equivalente aSystem.out.print(string+"\n")
.System.out.printf
toma como argumento strings con formatos. Probablemente te sea confuso a menos que hayas usadoprintf
en C. Un ejemplo:System.out.print("Tengo %d años y me llamo %s. Este es un número con 5 caracteres: '%05d'\n", 6, "Pablito", 42);
. Más información en Wikipedia
Java es un lenguaje tipado, hay que decirle a las variables de qué tipo van a ser. Como buen hijo de C tiene los tipos de números enteros (int
), números con decimales (float
o double
) y caracteres sólos (char
). También tiene otros tipos para facilitarnos la vida, como valores booleanos (boolean
) y Strings (String
). Este último en realidad no es un tipo, sino que un objeto de Java, pero apenas nos vamos a dar cuenta de eso.
A diferencia de otros lenguajes, para imprimir un número en pantalla no tuvimos que convertirlo antes de int
a String
o lo que sea: bastó con hacer System.out.println("Número: "+num);
y ese +
que concatena un número a un String también se encarga de convertirlo a String. Si quisiéramos imprimir sólo un número, un truco sucio muy utilizado es System.out.println(""+42)
. Más adelante incluso llamamos a System.out.println
sin argumentos, sólo para que imprima líneas vacías (hay mejores formas de hacerlo, pero es un ejemplo).
Después creamos un String y obtuvimos su largo con s.length()
. Esta función length()
es una función2 que tienen todos los String de Java. En el bloque siguiente, creamos un arreglo arr
(se utiliza la keyword new
para crear cosas) con toda la burocracia que tiene Java para crear objetos; incluso utilizamos el número num
como uno de los elementos del arreglo. Para saber su largo, arr
tiene la propiedad length
(no es una función, así que no se llama “length()”).
3.2. Arreglando el intento
Si utilizaste el mismo código, vas a ver la línea que dice Contenido arreglo: ...
imprime pura basura. Esto es porque los arreglos no tienen una representación directa a String. Esto se podría solucionar fácilmente con la librería java.util.Arrays
, pero en el curso no te dejan utilizarla, así que vamos a crear una solución a mano: Hay que recorrer el arreglo, y cada elemento concatenarlo en un String. Cambiemos nuestra clase Main para que tenga una función que haga esto:
class Main {
static String stringArreglo(int[] arreglo) {
String s = "[";
int n = arreglo.length;
s += arreglo[0];
int i = 1;
while (i < n) {
s += ", "+arreglo[i];
i++;
}
s += "]";
return s;
}
public static void main(String[] args) {
System.out.println("Voy a crear un número");
int num = 7;
System.out.println("Número: "+num);
System.out.println();
String s = "Hola, voy a crear un arreglo";
System.out.println("Largo string: "+s.length());
System.out.println("Contenido string: '"+s+"'");
System.out.println();
int arr[] = new int[] {4, 6, 2, num, 281, 42};
System.out.println("Largo arreglo: "+arr.length);
System.out.println("Contenido arreglo: '"+stringArreglo(arr)+"'");
}
}
Si lo corres ahora, va a funcionar por arte de magia. Hagámosle una disección a la magia paso por paso:
- Primero creamos una función con el encabezado
static String stringArreglo(int[] arreglo)
. ¿Por qué esstatic
? Bueno, prueba sacándole elstatic
. No va a funcionar, porque esta función la estamos llamando desdepublic static void main()
, y los métodos estáticos sólo pueden llamar métodos estáticos. ¿Por qué esString
? Pues porque retorna un String. En Java siempre hay que decir qué retornan tus funciones. Si no retornara nada (por ejemplo, una función que sólo imprime en pantalla), basta ponervoid
. ¿Por quéstringArreglo
? Porque me pareció que era un buen nombre para una función que toma un arreglo y devuelve una representación como String. - Dentro de la función, creamos un String
s
que sólo contiene un[
. Esto porque se me ocurrió que una buena forma de mostrar arreglos es rodeando sus elementos de [paréntesis cuadrados]. - Creamos la variable
n
que almacena el largo del arreglo. ¿Por qué? Bueno, perfectamente pudimos haber usadoarreglo.length
cada vez que necesite el largo, pero si hubiera necesitado ese número muchas veces, me da lata escribir arreglo punto length a cada rato, y tengo la costumbre de guardar ese número en unan
. - Después guardamos en el String (la representación de) el primer elemento del arreglo. ¿Por qué? Porque luego vamos a agregar
, <elemento>
en cada iteración, y si guardáramos todos los elementos así, obtendríamos un string[, 1, 2, 3]
. ¿Lo ves? La primera coma está de más. - Ahora vamos a guardar todos los elementos desde el índice 1 (que es el segundo, olvídate de Matlab aquí) iterando con un ciclo
while
. Básicamente dice guárdame el i-ésimo elemento dearreglo
(s += ", "+arreglo[i];
) desde el segundo (int i = 1;
) mientrasarreglo
tenga i elementos. Es importante eli++
de abajo, o si no estarías guardando eternamente el segundo elemento del arreglo, y nunca se cumpliría que \(i \geq n\), corriendo el programa hasta el infinito (o al menos hasta el Strings
llene la memoria de tu computador). - Le agregamos el corchete de cierre y lo retornamos. ¡Listo! Tienes una función que te deja ver una representación de tus arreglos, perfectamente funcionando, ¿no?
Pues no. Agrega en la parte final del main
la línea
System.out.println(stringArreglo(new int[] {}));
compila y corre; la línea new int[] {}
sólo crea un arreglo vacío (que no guarda en ninguna variable) y se lo pasa a la función.
3.3. Mi primera excepción
Felicidades, deberías tener tu primera Runtime Exception (excepción en tiempo de ejecución: “por más que haya compilado bien, Java no tenía la culpa de que esto haya fallado”). Veamos qué dice la excepción:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Main.stringArreglo(Main.java:6)
at Main.main(Main.java:36)
Leyendo desde abajo hacia arriba, la línea (36 en mi caso, depende de cuantos saltos de línea hayas puesto tú) del archivo Main.java
corresponde a System.out.println(stringArreglo(new int[] {}));
, que es justo la línea que agregamos recién. El siguiente llamado en el stack de la excepción corresponde a la línea 6, dentro de la función stringArreglo
. La línea que falla ahí dice s += arreglo[0];
.
¿Te diste cuenta del error? La misma máquina de Java nos está diciendo: ArrayIndexOutOfBoundsException: 0
. Excepción de índice fuera de rango: 0. Estamos buscando el primer elemento ¡de un arreglo que no tiene elementos!. Esto se soluciona con un if
:
if (n > 0) {
s += arreglo[0];
}
Listo, ahora la excepción no debería ocurrir, porque le estamos preguntando primero al arreglo si es que tiene algún elemento. Compila y corre, vas a ver que la pantalla muestra bien el []
, que es lo esperado.
3.4. Función arreglada
Una forma “más bonita” de recorrer el arreglo es cambiando el while
por un for
, con lo que la función stringArreglo
queda:
static String stringArreglo(int[] arreglo) {
String s = "[";
int n = arreglo.length;
if (n > 0) {
s += arreglo[0];
}
for (int i=1; i < n; i++) {
s += ", "+arreglo[i];
}
s += "]";
return s;
}
Ah, se me olvidaba: el var += algo
es equivalente a var = var + algo
, y var++
es el var = var + 1
.
<dato curioso>
Los while
son equivalentes a los for
: el primer elemento del for
corresponde a una variable declarada antes del while
, el segundo elemento del for
equivale a la condición del while
, y el último elemento del for
equivale a la última línea del while
. La única diferencia sería que la variable int i
deja de estar declarada fuera del for
y no así en el while
, pero eso se soluciona encerrando el int i=1; while(...) {... i++;}
entre otro par de {
y }
.
</dato curioso>
Listo, eso es todo en la primera parte de esta miniguía. En la segunda parte (update: aquí) planeo colocar cosas sobre códigos con más de una clase, y métodos no estáticos.