Enum en Java

Estándar

El día de hoy tuve que lidiar con un nuevo tipo de dato en el lenguaje de programación Java: el tipo Enum.

Conociendo los enum

Según la documentación de Java sobre este tipo de dato, se dice que: “un tipo enum es un tipo de dato especial que permite a una variable ser un conjunto de constantes predefinidas”. En otras palabras, se podría decir que un tipo enum es un tipo de dato que el usuario define, el cual sólo puede tomar valores de una lista (véase lista como cualquier otra cosa menos un tipo List).

Y nos podemos preguntar: ¿para qué me serviría un enum? Bueno, respondo con preguntas: ¿cuántas veces necesitaste tener a la mano una lista de los días de la semana, los puntos cardinales?, ¿o alguna vez creaste un programa el cual trabaja con licencias, y quieres saber de qué tipo es la que tiene el usuario final? Bien, más claro no puedo decir: un tipo enum es un array de constantes, que tienen el mismo tipo que el enum.

¿Un ejemplo? Bien, hagamos un enum con los puntos cardinales:

package enums.punto;

public enum PuntoCardinal {
    NORTE,
    SUR,
    ESTE,
    OESTE
}

Ok, ese es un ejemplo simple. Y vemos algo nuevo: ya no tenemos nuestro “class”, en su lugar tenemos un “enum”. Deducimos entonces que un enum es una clase, así que debemos tratarla como tal. Ahora veamos cómo probarlo:

package enums.punto;

public class PruebaEnumPuntoCardinal {
    
    public static void main(String[] args) {
        
        PuntoCardinal p = PuntoCardinal.SUR;
        
        // Forma fácil de hacerlo, son constantes
        if (p == PuntoCardinal.SUR) {
            System.out.println("Perú queda en el SUR.");
        }
        
        // Forma POO para trabajar
        if (PuntoCardinal.SUR.equals(p)) {
            System.out.println("Perú queda en el SUR.");
        }
        
    }
    
}

Como podremos ver, podemos usar la POO para comprobar valores enum, o sino lo que aprendimos mucho antes y vemos en cualquier lenguaje: nuestro querido “==” 🙂

Un enum no es instanciable

Perfecto, pero ahora queremos hacer algo mucho más robusto, pues no es divertido aprender los puntos cardinales con Java. Entonces, ¿qué tal si asignamos un número a cada día de la semana?

package enums.semana;

public enum DiaSemana {
    
    DOMINGO(0),
    LUNES(1),
    MARTES(2),
    MIERCOLES(3),
    JUEVES(4),
    VIERNES(5),
    SABADO(6);
    
    public final int nroDia;
    
    private DiaSemana(int nroDia) {
        this.nroDia = nroDia;
    }
    
    public int getNroDia() {
        return nroDia;
    }
    
    public String getNombreDia() {
        return name();
    }
    
}

Según el código, podemos observar que a pesar que un enum es una clase, no es instanciable. Por lo tanto, si deseas prueba a hacer un “new DiaSemana(4)” y no podrás. Luego, otra pregunta que puede surgir es: ¿dónde declaraste el método name() al que llamas desde getNombreDia()? Mi respuesta es que todo enum hereda de la clase Enum, y viendo en la documentación de Java sabremos más. Bueno, probemos el código anterior:

package enums.semana;

public class PruebaEnumDiaSemana {
    
    public static void main(String[] args) {
        
        DiaSemana d = DiaSemana.DOMINGO;
        
        StringBuilder sb = new StringBuilder();
        sb.append("Hoy es ");
        sb.append(d.getNombreDia());
        sb.append(" y es número ");
        sb.append(d.getNroDia());
        sb.append(".");
        
        System.out.println(sb);
        
    }
    
}

Métodos heredados de Enum

Como ya dije antes, todo tipo enum hereda de la clase Enum de Java. Los métodos que hereda de ella son:

  • public final boolean equals(Object other): Devuelve TRUE si el objeto especificado es igual a esta constante. Sobrescribe el método “equals” de Object.
  • public final String name(): Devuelve en nombre de esta constante, tal y como fue declarada.
  • public final int ordinal(): Devuelve la posición de la constante según la declaración de éstas. A la primera constante declarada se le asigna 0.
  • public String toString(): Devuelve lo mismo que name(), pero sobrescribe “equals” de Object.
  • public static enumConstant[] values(): Devuelve un array con las constantes declaradas.

El porqué hice esto

Me animé a leer esto luego de tener que lidiar con algún código sacado de Zend Studio 10.5, el cual expongo:

package com.zend.php.core.core.key;

public enum SKU {
    
    SUBSCRIPTION(1, "Zend Studio Subscription"),
    IBM(2, "Zend Studio Standard for IBM-I"),
    PERPETUAL(3, "Zend Studio Perpetual");
    
    public final int index;
    public final String description;
    
    private SKU(int index, String description) {
        this.index = index;
        this.description = description;
    }
    
    public static final SKU byIndex(int index) {
        SKU[] values = values();
        for (SKU sku : values) {
            if (sku.index == index) {
                return sku;
            }
        }
        return null;
    }
    
}

Y luego de ver un código tipo “parche” en el que el creador intentó igualar el enum con una clase, preferí aprender algo sobre los enum antes que igualarlo con clases.

Bien, eso ha sido todo. Como siempre, los archivos usados están en este link.

Anuncios

Solución a la práctica de Algoritmos I – Grupo A

Estándar

La práctica tomada por el profesor el día de hoy nos sorprendió un poco con el tiempo dado para resolverla. Aún así, logré ver que la mayoría logró resolverla en una escala media.

El trabajo que ahora tenemos consta en desarrollar la práctica. Y como es una oportunidad para mejorar lo que hicimos durante el tiempo dado, pues aquí expongo la mejora de mi código (el que hice en clase me lo reservo).

Codificación

public class Fraccion {
    
    private int num;
    private int den;
    
    /**
     * Crea una nueva Fraccion.
     */
    public Fraccion() {
        num = 0;
        den = 1;
    }
    
    /**
     * Copia la Fraccion en f a esta Fraccion.
     * @param f Fraccion a copiar
     */
    public Fraccion(Fraccion f) {
        num = f.num;
        den = f.den;
    }
    
    /**
     * Inicializa los valores de esta Fraccion.
     * @param num numerador
     * @param den denominador
     */
    public Fraccion(int num, int den) {
        this.num = num;
        this.den = den;
    }
    
    /**
     * Obtiene el numerador de esta Fraccion.
     * @return numerador
     */
    public int getNum() {
        return num;
    }
    
    /**
     * Obtiene el denominador de esta Fraccion.
     * @return denominador
     */
    public int getDen() {
        return den;
    }
    
    /**
     * Asigna el numerador de esta Fraccion.
     * @param num numerador a asignar
     */
    public void setNum(int num) {
        this.num = num;
    }
    
    /**
     * Asigna el denominador de esta Fraccion.
     * @param den denominador a asignar
     */
    public void setDen(int den) {
        this.den = den;
    }
    
    /**
     * Suma dos Fracciones.
     * @param f segunda Fraccion a sumar
     * @return Fraccion suma
     */
    public Fraccion sumar(Fraccion f) {
        return new Fraccion(num * f.den + f.num * den, den * f.den);
    }
    
    /**
     * Multiplica dos Fracciones.
     * @param f segunda Fraccion a multiplicar
     * @return Fraccion producto
     */
    public Fraccion multiplicar(Fraccion f) {
        return new Fraccion(num * f.num, den * f.den);
    }
    
    /**
     * Simplifica una Fraccion.
     * @return Fraccion simplificada
     */
    public Fraccion simplificar() {
        int n = num;
        int d = den;
        int res;
        // Calculamos el MCD
        while (d != 0) {
            res = n % d;
            n = d;
            d = res;
        }
        return new Fraccion(num / n, den / n);
    }
    
    /**
     * Compara fracciones.
     * @param f Fraccion a comparar
     * @return true si esta Fraccion es mayor a f.
     */
    public boolean esMayor(Fraccion f) {
        if (num * f.den > f.num * den) {
            return true;
        }
        return false;
    }
    
    /**
     * Devuelve la Fraccion como cadena.
     * @return Fraccion como String
     */
    public String toString() {
        return num + "/" + den;
    }
    
}
import java.util.Random;
import java.util.Scanner;

public class PruebaFraccion {
    
    private static void generar(Fraccion[] v) {
        Random r = new Random();
        for (int i = 0; i < v.length; i++) {
            int num = r.nextInt(10);
            int den = r.nextInt(10);
            // El denominador no puede ser 0
            while (den == 0) {
                den = r.nextInt(10);
            }
            v[i] = new Fraccion(num, den);
        }
    }
    
    private static void mostrar(Fraccion[] v) {
        System.out.println();
        for (int i = 0; i < v.length; i++) {
            // No es necesario llamar a toString()
            // pues lo llama de manera automatica
            System.out.println(v[i]);
        }
        System.out.println();
    }
    
    private static Fraccion mayor(Fraccion[] v) {
        Fraccion mayor = new Fraccion(v[0]);
        // i = 1 porque ya asignamos arriba
        // la fraccion mayor a 0
        for (int i = 1; i < v.length; i++) {
            if (v[i].esMayor(mayor)) {
                mayor = new Fraccion(v[i]);
            }
        }
        return mayor;
    }
    
    private static Fraccion suma(Fraccion[] v) {
        Fraccion suma = new Fraccion(v[0]);
        // i = 1 tambien
        for (int i = 1; i < v.length; i++) {
            suma = suma.sumar(v[i]);
        }
        return suma;
    }
    
    private static Fraccion producto(Fraccion[] v) {
        Fraccion producto = new Fraccion(v[0]);
        // i = 1 tambien
        for (int i = 1; i < v.length; i++) {
            producto = producto.multiplicar(v[i]);
        }
        return producto;
    }
    
    public static void main(String[] args) {
        
        Scanner sc = new Scanner(System.in);
        
        System.out.print("Numero de elementos: ");
        int n = sc.nextInt();
        sc.close();
        
        Fraccion[] v = new Fraccion[n];
        
        generar(v);
        mostrar(v);
        
        // Tener en cuenta que el toString()
        // ya no debe ser llamado porque Java
        // automaticamente sabe llamarlo
        System.out.println("Fraccion mayor: " + mayor(v));
        System.out.println("Suma: " + suma(v).simplificar());
        System.out.println("Producto: " + producto(v).simplificar());
        
    }
    
}

Espero sus comentarios, observaciones, y otros 🙂

compareTo en JavaScript

Estándar

Todos alguna vez hemos estudiado los métodos de ordenamiento, si hemos visto lenguajes de programación. Y, los que lo hemos visto, nos podremos dar cuenta que no son difíciles de entender y aprender, siempre y cuando no nos den datos del tipo String. Esos sí que son problemáticos en su totalidad. Pues, uno al comparar dos números, puede establecer una relación de orden fácilmente. Ahora, aplica eso en una cadena. Puedes obtener el código ASCII del primer carácter, pero si te muestro “ANALGÉSICO” y “ANALÓGICO”, ¿qué haces?

Pensando en esto, es que decidí ver el código fuente de la clase String de Java, viendo cómo trabaja el compareTo. La verdad en un momento pensé que sería algo grande, y lo fue. Creo que se declaran variables hasta por las puras. Menos mal que en JavaScript no es necesario convertir un String a char[], sino de una sola usando String.charAt().

Entonces, aquí presento el código del prototipo “compareTo” de String, codificado en JavaScript:


String.prototype.compareTo = function( cadena ) {
  cadena += "";
  var l1 = this.length,
  l2 = cadena.length,
  limite = Math.min( l1, l2 ),
  k = 0,
  c1,
  c2;
  while ( k < limite ) {
    c1 = this[ k ];
    c2 = cadena[ k ];
    if ( c1 !== c2 ) {
      return c1.charCodeAt( 0 ) - c2.charCodeAt( 0 );
    }
    k++;
  }
  return l1 - l2;
};

Separar palabras de una frase en Java

Estándar

Muchas veces nos vemos en la necesidad de separar una frase en palabras, para así poder comprobar con algún diccionario su correcta escritura, si son o no malas palabras, entre otros.

Java, por su parte, provee de muchas funciones para el tratamiento de esto. Dentro de ellas, podemos encontrar el método split de la clase String. También podemos hacerlo con expresiones regulares. Pero la verdad es que para los que somos principiantes en Java, nos es muy difícil conocer todo esto.

Es por ello, que aquí presento una forma simple de separar una frase en palabras, teniendo en cuenta las peculiaridades de una frase, y además pensando que la frase no contiene espacios por delante y por detrás. Si alguien logra mejorar esto, por favor publicarlo en los comentarios 🙂

package vectores;

import java.util.Scanner;

/**
 * Clase para separar palabras de una frase.
 * @author Bryan Horna <bryanjhv@gmail.com>
 *
 */
public class Separar {
	
	static Scanner sc = new Scanner(System.in); // El Scanner
	
	/**
	 * Separa la frase en palabras.
	 * @param s La cadena a separar.
	 * @return Cadena en partes.
	 */
	public static String[] separarFrase(String s) {
		int cp = 0; // Cantidad de palabras
		
		// Recorremos en busca de espacios
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) == ' ') { // Si es un espacio
				cp++; // Aumentamos en uno la cantidad de palabras
			}
		}
		
		// "Este blog es genial" tiene 3 espacios y 3 + 1 palabras
		String[] partes = new String[cp + 1];
		for (int i = 0; i < partes.length; i++) {
			partes[i] = ""; // Se inicializa en "" en lugar de null (defecto)
		}
		
		int ind = 0; // Creamos un índice para las palabras
		for (int i = 0; i < s.length(); i++) {
			if (s.charAt(i) == ' ') { // Si hay un espacio
				ind++; // Pasamos a la siguiente palabra
				continue; // Próximo i
			}
			partes[ind] += s.charAt(i); // Sino, agregamos el carácter a la palabra actual
		}
		return partes; // Devolvemos las partes
	}
	
	public static void main(String[] args) {
		
		System.out.print("Ingrese una frase: ");
		String frase = sc.nextLine(); // Guardamos la frase o texto
		
		String[] p = separarFrase(frase); // Separamos palabras
		
		for (int i = 0; i < p.length; i++) {
			System.out.println("Parte " + (i + 1) + ": " + p[i]); // Mostramos
		}
		
	}
	
}

Como siempre, puedes descargar este código completo desde aquí.

Histograma en Java

Estándar

Tras haber visto varios artículos por Internet, vi algunos interesantes acerca de cómo generar un histograma con asteriscos en Java.

La verdad me decepcioné demasiado al saber que no saben ni siquiera pensar para subir algún contenido. Sólo suben lo que piensan con un título sugestivo para así poder ganar un poco de dinero con las visitas en su blog. Parece que yo, sin ganar dinero, publico contenido de calidad antes que eso, que lo único que nos hace perder a la mayoría de estudiantes es tiempo.

En este artículo muestro el código de un programa que me pidieron en la Universidad, para generar un histograma básico mediante el ingreso y tratamiento de vectores.

Aquí expongo el código:

package vectores; // El paquete que estoy usando

import java.util.Scanner; // Para el ingreso de datos

public class Histograma {
	
	public static void generarV(int[] v) { // Generamos un vector
		for (int i = 0; i < v.length; i++) {
			v[i] = (int) (Math.random() * 101);
		}
	}
	
	public static void histogramaV(int[] v) { // Hace el histograma
		int[] rep = new int[v.length]; // Repeticiones
		for (int i = 0; i < v.length; i++) {
			int ca = 0; // Cantidad (frecuencia)
			for (int j = 0; j < v.length; j++) {
				if (v[i] == v[j]) {
					ca++;
				}
			}
			if (rep[i] == 0) { // Si aún no se ha repetido
				System.out.print(v[i] + ": ");
				for (int k = 0; k < ca; k++) {
					System.out.print("*"); // Un '*' por cada punto frecuencial
				}
				System.out.println();
			}
			for (int j = 0; j < v.length; j++) {
				if (v[i] == v[j]) {
					rep[j]++; // Si ya está visto esta parte
				}
			}
		}
	}
	
	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in); // Creamos el ingreso de datos
		
		System.out.print("Cantidad de elementos: ");
		int n = sc.nextInt(); // Almacenamos cantidad de elementos

		int[] v = new int[n]; // Creamos el vector

		generarV(v); // Lo generamos
		
		histogramaV(v); // Mostramos el histograma
		
	}
	
}

Sé que al código le falta optimizar ciertos aspectos. Aquel que logre esto, puede publicarlo en los comentarios. Así contribuiría con todos los lectores 🙂
Por cierto, puedes descargar el código desde aquí (me brindas unos cuantos céntimos al hacer clic).