sábado, 16 de junio de 2012

JDBC: Java y las bases de datos

votar
JDBC  es el nombre de una librería Java que posee un conjunto de interfaces y clases utilizadas para escribir programas Java que pueden acceder y manipular bases de datos relacionales. Al utilizarla, las aplicaciones escritas en Java pueden ejecutar sentencias SQL, presentar los datos en interfaces amigables para los usuarios y cambiar datos en la base de datos.

JDBC puede ser utilizada tanto con bases de datos MySQL, como bases de datos Oracle o con Access de Microsoft. Pero para poder utilizar esta librería y acceder a las bases de datos en los programas hay que instalar los drivers correspondientes. Puesto que un driver JDBC es la interfaz que facilita las comuncaciones entre JDBC y la base de datos, es un driver específico de la base de datos. Así pues, hace falta un MySQL JDBC Driver para acceder a una base de datos MySQL, un Oracle JDBC Driver para acceder a una base de datos Oracle, pero para acceder a una base de datos Access, el JDK incluido trae un puente o Bridge JDBC-ODBC. ODBC es una tecnología desarrollada por Microsoft para el acceso a las bases de datos en la plataforma Windows. A su vez, un driver ODBC viene preinstalado en Windows, así que el puente JDBC-ODBC permite el acceso a cualquier base de datos ODBC de un programa Java.

Los drivers de MySQL y Oracle son:
   MySQL: com.mysql.jdbc.Driver
   Oracle: oracle.jdbc.driver.OracleDriver
que se pueden descargar de las compañías correspondientes. En concreto, el driver de MySQLestá en el archivo jar mysqljdbc.jar. Una vez descargado el driver, hay que añadirlo al classpath, ya sabéis: Equipo>>Propiedades>>Opciones avanzadas>>Variables del entorno...si lo habéis hecho al instalar Java, ya os lo sabéis de memoria.

Y ahora, ¿cómo se usa?. Bueno vamos a ver un ejemplo muy sencillito para que os hagáis una idea. Lo voy a hacer con MySQL, que es la base de datos que uso yo, pero también vale para cualquiera de las otras. Suponed que tenéis una base de datos de un colegio, y en ella una tabla con los datos personales de los estudiantes. Como este blog no es sobre SQL, vamos a hacerlo sin muchas explicaciones: 

CREATE DATABASE colegio;
USE colegio;
CREATE TABLE alumnos(
     nombre varchar(15),
     primer_apellido varchar(15),
     segundo_apellido varchar(15),
     nacimiento date,
     teléfono char(10),
     dirección varchar(20),
     );

Y a continuación la pobláis con los datos de alumnos imaginarios. Ahora vamos a crear un programa que se conecte a la base de datos y de como salida solo los nombres y los apellidos de los alumnos.



import java.sql.*; //no olvidéis esto
public class EjemploJdbc{
   public static void main(String[] args)throws SQLException, ClassNotFoundException{ //podemos usar try-catch, pero así el ejemplo es más simple
      Class.forName("com.mysql.jdbc.Driver"); //se carga el driver
      System.out.println("Driver cargado"); 

      //Ahora vamos a establecer una conexión
      Connection conexión = DriverManager.getConnection
       ("jdbc:mysql://localhost/colegio","usuario","contraseña");
     //Hemos puesto la base de datos con la que queremos conectar y el nombre de usuario y contraseña que usamos con ella
      System.out.println("Base de datos conectada");

      Statement st = conexión.createStatement();
      ResultSet resultado = st.executeQuery
         ("select nombre,primer_apellido,segundo_apellido from alumnos");

      //iteramos
      while(resultado.next()){
         System.out.println(resultado.getString(1)+ "\t"+ resultado.getString(2) + "\t" + resultado.getString(3));
      }
      conexión.close(); //cerramos la conexión
   }
}


La salida serán los nombres de los alumnos que hayáis introducido en la tabla. Ya véis que es muy sencillo. Se pueden usar cualquier sentencia SQL dentro del método executeQuery(String sql). El resultado será adjudicado a ResultSet. 


Por supuesto JDBC es mucho más amplio, y en otra ocasión veremos alguna de sus interfaces y sus clases. Por ahora, espero que esto os haya servido para poder conectar vuestros programas Java a vuestras bases de datos.

sábado, 9 de junio de 2012

Formateo de textos en Java

votar
Para formatear textos, Java utiliza los métodos format() y printf(), que en realidad tienen las mismas funcionalidades. Por ejemplo, podemos hacer
   
   System.out.printf(%s,%s, "Super","ejemplo");

o

   String str = String.format(%s,%s,"Super","Ejemplo");

A los que vengáis de C o algún otro lenguaje esto os resultará familiar, ya que es similar a los métodos printf y sprintf. Eso sí, tened en cuenta que Java arroja una excepción si encuentra un String mal formateado.

A los que veis esto por primera vez y os suena a chino, os lo voy a explicar con más detalle.
Supongamos que tenéis un texto:

   String s = "El número de visitantes el "+nombredia+" fue de "+numerovisitantes;

Formateando, lo dejaríamos así:

   String s = String.format("El número de visitantes el %s fue de %d", nombredia, numerovisitantes);

¿Pero que son %s y %d?
Bueno, eso son carecteres de conversión y los veremos en un momento, ahora sólo os digo que s significa string y d un número entero.

La clase java.util.Formater es la que proporciona la base para la representación de texto formateado a través de sus métodos

   format(String format, Object...args);
   format(Locale l, String format, Object...args);

El texto resultante puede ser un String, un StringBuilder, un archivo o cualquier OutputStream.
Las dos versiones del método format() también son utilizadas por las clases java.io.PrintStream y java.io.PrintWriter, que además tienen dos versiones similares del método printf().
La clase String tiene un método format(), pero es estático.

La sintaxis es la siguiente: el primer parámetro del método es el texto y los especificadores de formato, seguido de un array de argumentos.
Los especificadores se escriben en el siguiente orden (entre corchetes los que son opcionales):

   %[argument_index] [flags] [width] [precision] conversion

donde % marca el inicio de un especificador.
[argument_index] indica cuál de los argumentos se va a utilizar. Se hace con un número seguido de $. Por ejemplo:

   String str = "Año, mes, día: %3$s-%2$-%1$s";
   System.out.printf(str, 5, "Febrero", 2012);

producirá la salida

   Año, mes, día: 2012-Febrero-5

Los flags o banderas son opcionales, e indican (los coloco entre comillas aquí, pero no las llevarían en el código):

   "-":  justifica el argumento a la izquierda.
   "#":  incluye un radical para enteros y una coma para decimales.
   "+":  incluye el signo(+ o -).
   "  ":  espacio en los valores positivos.
   "0":  se llenan los espacios con ceros en los valores positivos.
   ",":  usa un separador de grupo específico según la zona geográfica.
   "(":  encierra los números negativos en paréntesis.

Width indica el número mínimo de caracteres que tendrá la salida. 
Precision indica el número máximo de dígitos después de la como en un decimal.

El especificador conversion es obligatorio e indica de qué tipo es el argumento. Los más usados son

   b: boolean.
   c: carácter Unicode.
   d: número entero.
   f: número decimal
   s: String.
   t: fecha y hora.

Veamos ahora un par de ejemplos para que lo acabéis de entender.

 int in = 1234;

 String s = String.format("El número es: %08d", in);

 System.out.println(s);


La salida será: 


   00001234


Vemos que se han añadido ceros a la izquierda, porque le hemos dado una anchura de ocho dígitos y queremos que lo que falta lo ocupen ceros.


public class EjempoFormat{
   public static void main(String[] args){
      String nombre = args[0];
      String apellido = args[1];
      String s2 = String.format("Datos:\n%1$-10s\n%2$-10s\n",nombre,apellido);
      System.out.println(s2);
   }
}

En este caso la salida serán los argumentos que introduzcamos nosotros alineados a la izquierda. Por ejemplo:


Datos:
Alfonso
López


Se pueden hacer por supuesto cosas mucho más complicadas, pero espero que esto al menos os sirva para empezar. :-)

viernes, 1 de junio de 2012

Java Regex

votar
   Vamos a tratar en esta entrada las expresiones regulares en Java. Será sólo una aproximación, porque esto de las expresiones regulares, regex para abreviar, es un lenguaje en sí mismo y da para varios libros. Las expresiones regulares no se utilizan sólo en Java, si no también en otros lenguajes de programación, como Pearl o Groovy, y por supuesto las puedes usar en Word o Writer. Sin embargo, en cada lenguaje existen ligeras diferencias a la hora de usarlas. Como si no fuera ya bastante complicado el tema. Lo que sí tienen en común es que se usan para encontrar y manipular texto.

Una expresión regular sustituye desde un simple carácter a oraciones enteras que deseas encontrar en un texto. Evidentemente, si quieres encontrar más de una palabra, o incluso una palabra larga, no es muy práctico tener que escribirlas literalmente.

Java tiene dos clases, dentro del paquete java.util.regex, especializadas en este tipo de manipulación de texto: Matcher y Pattern. Pattern compila una expresión regular para crear un patrón. Matcher utiliza dicho patrón para hallar coincidencias en el texto.
Por ejemplo:

String texto = “Este es el texto en el que vamos a buscar un patrón”;
String patrónDeTexto = “.*el.*”; //.* significa cero o más caracteres antes y después de la palabra.
Pattern patrón = Pattern.compile(patrónDeTexto); //creamos una instancia de Pattern
Matcher match = patrón.matcher(texto); //creamos una instancia de Matcher
boolean b = match.matches();
System.out.println(“Coincide: “+ b);

Si la expresión regular sólo la vamos a usar una vez, podemos utilizar el método matches() con Pattern sin necesidad de una instancia de Matcher, simplificando lo anterior así:

String texto = “Este es el texo en el que vamos a buscar un patrón”;
String patrónDeTexto = “.*el.*”;
boolean b = Pattern.matches(patrónDeTexto, texto);
System.out.println(“Coincide: “+b);

lo que nos daría la misma salida que en el caso anterior:
Coincide: true


Supongamos ahora que queremos saber exáctamente cuántas coincidencias hay en el texto de la palabra “el” y en qué lugar se encuentran. Para ello utilizaremos los métodos de Matcher find(), start() y end(), teniendo en cuenta que el índice comienza en cero y que los espacios en blanco también cuentan como caracteres.

String texto = “Este es el texto en el que vamos a buscar un patrón”;
String patrónDeTexto = “el”; //queremos saber cuántas veces aparece esta palabra.
Pattern patrón = Pattern.compile(patrónDeTexto);
Matcher match = patrón.matcher(texto);
int contador = 0;
while (match.find()){
contador++;
System.out.println(“Coincidencia: “ + contador + “ de ” + match.start() + “ a ” + matcher.end());
}

La salida en este caso será la siguiente:
Coincidencia: 1 de 8 a 10
Coincidencia: 2 de 20 a 22

Otro método interesante es split(), utilizado para separar el texto en distintas líneas, de esta manera:

String texto = “Este es el texto, en el que vamos a buscar, un patrón”);
String patrónDeTexto = “,”;
Pattern patrón = Pattern.compile(patrónDeTexto);
String[] split = patrón.split(texto);
for(String palabras : split){
System.out.println(palabras);
}

La salida en este caso es:
Este es el texto
en el que vamos a buscar
un patrón

Hasta ahora hemos visto unos cuantos métodos de las clases Pattern y Matcher, pero poco sobre las expresiones regulares en sí. Pero como ya hemos dicho, utilizar expresiones literales suele ser muy inconveniente. Veamos ahora algunas de las expresiones regulares más utilizadas en Java.

.    equivale a cualquier carácter
\d equivale a cualquier dígito
\D equivale a cualquier carácter no dígito
\s equivale a un espacio en blanco
\S equivale a cualquier carácter excepto un espacio en blanco
\w equivale a cualquier letra
\W equivale a cualquier carácter excepto letras
[abc] equivale a a, b o c (o cualquier otro carácter que se indique)
[^abc] equivale a cualquier carácter excepto a, b o c
[a-zA-Z] equivale a cualquier carácter de la a a la z o de la A a la Z, todos inclusive
[a-d[m-p]] equivale a cualquier carácter de la a la d o de la m a la p
[a-z&&[def]] equivale a d, e o f
[a-z&&[^bc]] equivale a cualquier carácter de la a a la z excepto b o c
[a-z&&[^m-p]] equivale a cualquier carácter de la a a la z excepto los que van de la m a la p


Además, en java regex se utilizan cuantificadores para indicar el número de veces que se repiten los caracteres buscados. Estos cuantificadores se denominan greedy, reluctant y possessive. Para indicar el cuantificador greedy, siendo X un carácter cualquiera, se escribe:
X* para buscar coincidencias de cero o más X
X? para buscar coincidencias de una o ninguna X
X+ para buscar coincidencias de una o más X

Para denotar el cuantificador reluctant, a los signos anteriores se añade ?, de esta manera:
X*?
X??
X+?
Y para el cuantificador possessive, el signo +:
X*+
X?+
X++

¿Cómo funcionan estos cuantificadores? Bueno, el cuantificador greedy “lee” todo el texto de una vez y luego, de derecha a izquierda, se va deshaciendo de caracteres y vuelve a leer lo que queda una y otra vez hasta encontrar una coincidencia. El cuantificador reluctant, en cambio, empieza leyendo el texto de iquierda a derecha hasta hallar la coincidencia buscada. El cuantificador possessive lee el texto entero como el greedy, pero solo una vez, y si no haya una coincidencia esa vez, no sigue buscando más.

Veamos esto con un ejemplo. Supongamos que tenemos el siguiente texto “ID usuario Nombre usuario” y buscamos cero o más coincidencias de la siguiente expresión regular .io(cualquier carácter seguido de io)
Greedy: .*io. Leería el texto entero, que no está seguido de io, e iría “soltando” caracteres hasta que encontrase ID usuario Nombre usuar, seguido de los caracteres io que habría soltado y encontraría una coincidencia:
ID usuario Nombre usuario.
Reluctant: .*?io. Iría leyendo el texto de izquierda a derecha y encontaría dos coincidencias:
ID usuario
Nombre usuario
Possessive: .*+io. Leería todo el texto, pero solo una vez, y claro, como el texto no está seguido de io, no encontaría ninguna coincidencia.

Como hemos dicho, esto solo es una breve aproximación a las expresiones regulares en Java, pero esperamos que os sirva para ir practicándolas, así como a entender cómo funcionan las clases Pattern y Matcher.