Archivo de la categoría Java/Programación

Tutorial H2 Database

Jueves, 19 de Junio de 2008

La base de datos H2 es un base de datos relacional programada integramente en Java. Una de las características más importantes a consecuencia de esto es que podemos integrarla completamente en nuestras aplicaciones Java y acceder a a ella lanzando SQL directamente, sin tener que pasar por una conexión a través de sockets, como ocurirría con MySQL, Oracle, Postgress, etc. (aunque también es posible utilizarla a través de conexiones JDBC externas). Esto implica una mayor velocidad y una mejor integración, como ahora veremos.
Cuando trabajamos con la base de datos dentro de nuestra aplicaciones, se llama modo “embedded” (incrustado). Una vez que nuestra aplicación ha abierto la base de datos para trabajar con ella, esta queda fisicamente bloqueada, no permitiendo que otro motor H2 (en otra aplicación Java por ejemplo) pueda acceder a ella. Esto permite mantener la integridad del fichero físico de la base de datos, ya que si dos motores H2 escribieran a la vez podrían corromperla.

Usar y crear bases de datos incrustadas con H2 desde Java es realmente facil. Primero tenemos que bajarnos el último jar de http://www.h2database.com e incluirlo en nuestro CLASSPATH (o en el directorio WEB-INF/lib de nuestra aplicación WAR).

El siguiente código abre una conexión contra una base de datos, definiendo donde se encuentra físicamente en nuestro disco, sin tener que especificar ningún host, ip o puerto, ya que no hay conexión a través de sockets, sino que se accede directamenete al disco.

import java.sql.*;
public class Test {
  public static void main(String[] a) throws Exception {
    Class.forName("org.h2.Driver");
    Connection conn = DriverManager.getConnection("jdbc:h2:/home/vilches/h2/test", "sa", "");
  }
}

Si al abrir una conexión no existe físicamente los archivos de la base de datos, H2 los creará. Por ejemplo:

/home/vilches/h2/test.2.log.db
/home/vilches/h2/test.data.db
/home/vilches/h2/test.index.db
/home/vilches/h2/test.trace.db

La ruta a la base de datos elegida es /home/vilches/h2/test. Esto significa que se utilizará el directorio /home/vilches/h2/ y que en ese directorio se crearán los ficheros de la base de datos, que empezarán por test.* y tendrán distintas extensiones. De esta manera, cambiando solo el nombre del fichero es posible tener varias bases de datos el el mismo directorio, ya que empezarán con nombres distintos (por ejemplo /home/vilches/h2/test y /home/vilches/h2/otro).

Una conexión por sesión es suficiente

Una de las mayores ventajas de usar H2 de forma embebida es que podemos utilizar conexiones sin necesidad de un pool de conexiones. Podemos, por ejemplo, utilizar una única conexión para toda nuestra aplicación y no cerrarla nunca (o cerrarla al salir de la aplicación). En caso de aplicaciones Web, podemos crear una conexión por sesión con un listener que implemente HtppSessionListener:

package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.io.*;
public class MySessionListener implements HttpSessionListener {
    public Connection openConnection() throws SQLException, ClassNotFoundException {
        Class.forName("org.h2.Driver");
        return DriverManager.getConnection("jdbc:h2:/home/vilches/h2/test", "", "sa");
    }

    public void sessionCreated(HttpSessionEvent se) {
        try {
            se.getSession().setAttribute("h2.connection", openConnection());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        try {
            Connection con = (Connection)se.getSession().getAttribute("h2.connection");
            con.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Para que funcione el listener es necesario darlo de alta en el web.xml:

<listener>
    <listener-class>test.MySessionListener</listener-class>
</listener>

Ahora, desde nuestros servlets o JSPs, podemos acceder a la conexión con:

Connection con = (Connection)se.getSession().getAttribute("h2.connection");

y podremos utilizarla sin preocuparnos por cerrarla.

Abriendo la base de datos al arrancar la aplicación

Una buena practica es abrir por lo menos una conexión al arrancar la aplicación, de esta manera nos aseguramos de que H2 abre fisicamente la base de datos en el disco y la bloquea para el resto de procesos. Para hacer esto, podemos ampliar el listener anterior para que implemente también ServletContextListener, el cual tiene dos métodos que se ejecutan cuando se crea y se destruye el contexto (es decir, se arranca y se para la aplicación web).

Además, vamos a definir la ruta de la base de datos como un parámetro del contexto en el WEB-INF/web.xml llamado “h2.database.path” que leeremos en el arranque (si el parámetro no existe, cogeremos la home del usuario actual con System.getProperty("user.home")) y utilizaremos para crear la url jdbc :

package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.io.*;

public class MySessionListener implements ServletContextListener,
    HttpSessionListener {

    // Constante para el nombre de los ficheros
    private final static String DBFILENAME = "test";

    String url;
    Connection globalConnection;

    public void contextInitialized(ServletContextEvent sce) {
        // Leemos el parametro del contexto
        String spath = sce.getServletContext().getInitParameter("h2.database.path");
        if (spath == null) {
            // Si no existe, es la home del usuario
            spath = System.getProperty("user.home");
        }
        try {
            Class.forName("org.h2.Driver");
            File dbfile = new File(spath, DBFILENAME);
            url = "jdbc:h2:file:" + dbfile.getAbsolutePath().replaceAll("\\", "/");
            globalConnection = openConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Connection openConnection() throws SQLException {
        return DriverManager.getConnection(url, "", "sa");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        try {
            globalConnection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void sessionCreated(HttpSessionEvent se) {
        try {
            se.getSession().setAttribute("h2.connection", openConnection());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void sessionDestroyed(HttpSessionEvent se) {
        try {
            Connection con = (Connection)se.getSession().getAttribute("h2.connection");
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Para que funcione el listener es necesario darlo de alta en el web.xml y definir el parámetro de contexto con la ruta :

<context-param>
    <param-name>h2.database.path</param-name>
    <param-value>/home/vilches/h2</param-value>
</context-param>
<listener>
    <listener-class>test.MySessionListener</listener-class>
</listener>

Creando tablas al arrancar por primera vez

Ahora supongamos que queremos crear una serie de tablas cuando hemos arrancado la base de datos, pero solo la primera vez, cuando la base de datos está vacía. Para hacer esto vamos a verificar, antes de abrir la primera conexión, si la base de datos existe. Y si no existe, crearemos las tablas (después de abrir la primera conexión). Modificaremos el método contextInitialized para que quede así:

public void contextInitialized(ServletContextEvent sce) {
    // Leemos el parametro del contexto
    String spath = sce.getServletContext().getInitParameter("h2.database.path");
    if (spath == null) {
        // Si no existe, es la home del usuario
        spath = System.getProperty("user.home");
    }

    // Comprobamos si no existe la base de datos
    boolean exists = new File(spath, DBFILENAME+".data.db").exists();

    try {
        Class.forName("org.h2.Driver");
        File dbfile = new File(spath, DBFILENAME);
        url = "jdbc:h2:file:" + dbfile.getAbsolutePath().replaceAll("\\", "/");
        globalConnection = openConnection();

        // Si no existe, llamamos al metodo initDb()
        if (!exists) {
            initDb();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Ahora solo queda implementar initDb() a nuestro gusto.

Ejecutando un script SQL desde Java

Una buena practica es crear un fichero de script con las sentencias SQL y ejecutarlo directamente, sin tener que implementar, una a una, las sentencias de creación de tablas en nuestro código. El siguiente código lee un fichero de script llamado squema-h2.sql.txt situado dentro de la carpeta de de clases (es decir en /WEB-INF/classes/squema-h2.sql.txt) y lo ejecuta. Dentro de este script podemos incluir sentencias para crear tablas y añadir registros. El script necesita que cada sentencia acabe en punto y coma “;”, permite partir las sentencias en más de una línea e ignora los comentarios (líneas que empiezan por “–”, “#” y “//”) y líneas en blanco.

private void initDb() throws SQLException, IOException {
    InputStream is = getClass().getClassLoader().getResourceAsStream("squema-h2.sql.txt");
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    Connection connection = null;
    try {
        connection = openConnection();
        String line = br.readLine();
        StringBuilder statement = new StringBuilder();
        while (line != null) {
            line = line.trim();
            if (!line.startsWith("--") && !line.startsWith("#") && !line.startsWith("//")) {
                statement.append(line);
                if (line.endsWith(";")) {
                    executeLine(connection, statement.toString());
                    statement = new StringBuilder();
                }
            }
            line = br.readLine();
        }
        if (statement.length() > 0) {
            executeLine(connection, statement.toString());
        }
    } finally {
        try {
            br.close();
        } catch (Exception e) {;}
        try {
            if (connection != null) connection.close();
        } catch (Exception e) {;}
    }
}

private void executeLine(Connection connection, String statement) throws SQLException {
    PreparedStatement pstmt = connection.prepareStatement(statement);
    pstmt.execute();
    pstmt.close();
    System.out.println("Ejecutando "+statement);
}

El script /WEB-INF/classes/squema-h2.sql.txt podría ser:

CREATE TABLE USUARIO (
	ID INT AUTO_INCREMENT,
	LOGIN VARCHAR(25) NOT NULL UNIQUE,
	PASSWORD VARCHAR(25) NOT NULL,
	NOMBRE VARCHAR(100) NOT NULL,
	EMAIL VARCHAR(50),
	WEB	VARCHAR(100),

	PRIMARY KEY(ID)
);

-- Esto es un comentario
// Esto también
# Y esto también lo es

insert into usuario values (null, 'admin','admin123','Alberto Vilches',
	'email@sitio.com', 'http://albertovilches.com');

(Para más información sobre la sintaxis SQL de creación de tablas de H2, consultar H2 SQL Grammar reference)

Finalmente, creamos un JSP de ejemplo que liste los registros de la tabla para ver si todo funciona correctamente:

<%@ page import="java.sql.*" %>
<html>
  <body>
  <%
      Connection con = (Connection) request.getSession().getAttribute("h2.connection");

      PreparedStatement stmt = con.prepareStatement("SELECT * FROM USUARIO");
      ResultSet rst = stmt.executeQuery();
      while (rst.next()) {
      %>

  <%=rst.getString("LOGIN")%>, mailto:<%=rst.getString("EMAIL")%><br/>

      <%
      }

  %>
  </body>
</html>

Resumen

Con esto ya tendríamos un acceso a base de datos muy ligero y rápido disponible en nuestras aplicaciones Web. La ruta de la base de datos irá definida en el parámetro “h2.database.path” en el web.xml. El listener se encargará de crear la base de datos con las todas las tablas y mantenerla siempre abierta mientras esté activa la aplicación Web. También tendremos en la sesión siempre una conexión disponible lista para usar.

Bájate el código de ejemplo completo: War de ejemplo con H2 incrustado

Crear una conexión JDBC

Jueves, 19 de Junio de 2008

Para acompañar al viejo post sobre PL-SQL Oracle desde Java (en algunos comentarios y mensajes) voy a explicar a continuación como establecer una conexión contra la base de datos sin usar un pool de conexiones.

1 Lo primero que necesitaremos son los drivers JDBC en formato jar, incluir este archivo jar en el CLASSPATH de nuestro proyecto y cargarlos en memoria:

Oracle: JDBC Download page Oracle

Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();

MySql: MySQL Connector J

Class.forName("com.mysql.jdbc.Driver").newInstance();

2 Para crear la conexión, necesitamos una url JDBC, la cual contiene toda la información necesaria para conectarse:

Oracle: necesitaremos saber el host (el nombre de la máquina o su IP), el puerto de escucha del listener de Oracle (1521 por ejemplo), el servicio o sid, el usuario y la clave. Diferentes formatos de la url JDBC pueden ser:

jdbc:oracle:thin:@host:puerto:sid
jdbc:oracle:thin:usuario/clave@host:puerto:sid
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=puerto)))(CONNECT_DATA=(SERVICE_NAME=servicio)(SERVER=SHARED)))
jdbc:oracle:thin:usuario/clave@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=puerto)))(CONNECT_DATA=(SERVICE_NAME=servicio)(SERVER=SHARED)))

Más información en FAQ JDBC Oracle: Connections

MySql: host (nombre de la máquina o su IP), puerto de escucha (3306 por defecto), nombre de la base de datos, usuario y clave. El formato de la url es:

jdbc:mysql://host:puerto/database
jdbc:mysql://host:puerto/database?user=usuario&password=clave

(Más información en MySql JDBC Reference)

Una vez tengamos la url JDBC, podemos crear la conexión contra la base de datos:

Connection connection = DriverManager.getConnection(ulr, usuario, clave);

Si la url ya contiene el usuario y la clave (hay formatos que ya la llevan):

Connection connection = DriverManager.getConnection(ulr);

Con el objeto connection ya podemos trabajar, sin olvidarnos de que una vez hemos acabado, hay que cerrar la conexión. Esto es muy importante hacerlo, ya que si se queda abierta, estamos desaprovechando recursos, creando lo que se llama connection leaks (conexiones perdidas) con la base de datos.
La mejor forma de hacerlo es englobar todo el código en una estructura try/catch/finally y efectuando el cierre de la conexión en el finally. De esta manera nos aseguramos de que falle o no falle el código, se cerrará la conexión.

Connection connection;
try {
    // ...
    connection = DriverManager.getConnection(ulr);
    // ...
} finally {
    if (connection != null) {
        try {
            connection.close();
        } catch (SQLException e) {
			      e.printStackTrace();
        }
    }
}

Veamos ahora un par de ejemplos completo. Para Oracle definimos una url que incluye el usuario y la clave, por lo que no necesitaremos pasarle esta información en el método getConnection():

import java.sql.*;

public class OracleConnection {
    public static void main(String args[]) {

        String usuario = "vil";
        String password = "secreta";

        String host = "localhost"; // tambien puede ser una ip como "192.168.1.14"
        String puerto = "1521";
        String sid = "prueba";

        String driver = "oracle.jdbc.driver.OracleDriver";

        String ulrjdbc = "jdbc:oracle:thin:" + usuario + "/" + password + "@" + host + ":" + puerto + ":" + sid;

        Connection connection = null;
        try {
            Class.forName(driver).newInstance();
            connection = DriverManager.getConnection(ulrjdbc);

            // Ya tenemos el objeto connection creado

            ResultSet result = connection.createStatement().executeQuery("SELECT 'hola mundo' FROM DUAL");
            result.next();
            System.out.println(result.getString(1));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                }
            }
        }
    }
}

Y para MySQL (usaremos una url sin usuario y clave, por lo que pasaremos esta información al método getConnection):

import java.sql.*;

public class MySQLConnection {
    public static void main(String args[]) {

        String usuario = "vil";
        String password = "secreta";

        String host = "localhost"; // tambien puede ser una ip como "192.168.1.14"
        String puerto = "3306";
        String database = "prueba";

        String driver = "com.mysql.jdbc.Driver";

        String ulrjdbc = "jdbc:mysql://" + host + ":" + puerto + "/" + database;

        Connection connection = null;
        try {
            Class.forName(driver).newInstance();
            connection = DriverManager.getConnection(ulrjdbc, usuario, password);

            // Ya tenemos el objeto connection creado

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                }
            }
        }
    }
}

Resumen para crear una conexión con cualquier base de datos:

  • Insertar en el CLASSPATH el jar con los drivers de nuestra base de datos (drivers Oracle, drivers MySQL o buscar en Google “drivers jdbc basededatos”)
  • Cargar los drivers con Class.forName(sdriver).newInstance();, siendo sdriver un String con la clase del driver.
  • Crear la conexión con DriverManager.getConnection(ulrjdbc, usuario, password);, siend urljdbc una url con el formato que define la propia base de datos (Oracle: jdbc:oracle:thin:@host:puerto:sid, MySQL: jdbc:mysql://host:puerto/database o buscar en Google “jdbc url basededatos”)
  • Cerrar siempre la conexión dentro del finally

Parando Tomcat 5/6 desde Linux

Jueves, 8 de Mayo de 2008

Con algo tan sencillo como esto:

echo SHUTDOWN | nc localhost 8005

Si queremos parar Tomcat en otra máquina, cambiar “localhost” por su nombre o IP. Este sistema de parada es mejor que un kill -9 y mucho más rápido que la parada que realiza catalina.sh stop
De hecho, podemos cambiar este script para que realice la parada de esta manera, comentando las líneas que invocan la clase org.apache.catalina.startup.Bootstrap con el parámetro stop, de esta manera:

#  "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS 
#    -Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" 
#    -Dcatalina.base="$CATALINA_BASE" 
#    -Dcatalina.home="$CATALINA_HOME" 
#    -Djava.io.tmpdir="$CATALINA_TMPDIR" 
#    org.apache.catalina.startup.Bootstrap "$@" stop

echo SHUTDOWN | /bin/nc localhost 8005

El truco no es mío, lo he visto en groovygrails.de

Como reconocer a un buen programador

Miércoles, 12 de Marzo de 2008

Traducido por Info soldier

Indicadores positivos:

  • Le apasiona la tecnología
  • Programa en su tiempo libre, es su hobby
  • Hablará largo y tendido de cualquier tema técnico si se le pregunta
  • Ha tenido proyectos personales significativos a través de los años
  • Aprende nuevas tecnologías por si solo
  • Tiene opiniones fuertes sobre cual tecnología es la mejor para varios usos
  • Se siente incomodo trabajando con tecnologías que el crea no son “correctas”
  • Puede mantener una buena conversación en cualquier variedad de temas, no tan solo aquellos que sean técnicos
  • Empezó a programar mucho antes de entrar a la universidad o al trabajo
  • Tiene proyectos personales grandes que no necesariamente aparecen en el cv
  • Conoce de una gran variedad de tecnologías (las cuales no necesariamente están en el cv)

Indicadores negativos:

  • Solo programa mientras está en el trabajo
  • No le gusta hablar de programación, aunque se le pregunte
  • Aprende nuevas tecnologías cuando la compañía lo envía a tomar cursos
  • Usa la tecnología que le indiquen, cualquier tecnología es “buena”
  • Empezó a programar en la universidad
  • Toda su experiencia en programación está en su cv
  • Enfocado en uno o dos plataformas de programación (ejemplo: todo lo que tiene que ver con aplicaciones de java) sin ninguna experiencia fuera de esa plataforma.

Original en ingles

Programadorus Tremendus

Martes, 15 de Enero de 2008

lambdaward.PNG

(Vía Secret Geek)

Un tetris en 560bytes

Lunes, 10 de Diciembre de 2007

Con este simple código, un Tetris completamente funcional, con tan solo 560 bytes.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
<body onKeyDown=K=event.keyCode><script>X=[Z=[B=A=12]];h=e=K=t=P=0;function Y()
{C=[d=K-38];c=0;for(i=4;i--*K;K-13?c+=!Z[h+p+d]:c-=!Z[h+(C[i]=p*A-Math.round(p/
A)*145)])p=B[i];!t|c+4?c-4?0:h+=d:B=C;for(f=K=i=0;i<4;f+=Z[A+p])X[p=h+B[i++]]=1
if(e=!e){if(f|B){for(l=228;i--;)Z[h+B[i]]=k=1;for(B=[[-7,-20,6,17,-9,3,6][t=++t
%7]-4,0,1,t-6?-A:-1];l--;h=5)if(l%A)l-=l%A*!Z[l];else for(P+=k++,j=l+=A;--j>A;)
Z[j]=Z[j-A]}h+=A}for(i=S="";i<240;X[i]=Z[i]|=++i%A<2|i>228)i%A?0:S+="<br>",S+=X
[i]?"■":"_";document.body.innerHTML=S+P;Z[5]||setTimeout(Y,99-P)}Y()</script>
</body>
</html>

Puedes verlo funcionando aquí: http://zapanet.info/blog/game/tetorisu.html

Abrir una url en un navegador desde Java

Miércoles, 24 de Octubre de 2007

Sacado del código fuente de H2, clase org.h2.util.StartBrowser

    public static void openURL(String url) {
        String osName = System.getProperty("os.name");
        try {
            if (osName.startsWith("Windows")) {
                Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
            } else if (osName.startsWith("Mac OS X")) {
                // Runtime.getRuntime().exec("open -a safari " + url);
                // Runtime.getRuntime().exec("open " + url + "/index.html");
                Runtime.getRuntime().exec("open " + url);
            } else {
                System.out.println("Please open a browser and go to "+ url);
            }
        } catch (IOException e) {
            System.out.println("Failed to start a browser to open the url " + url);
            e.printStackTrace();
        }
    }

Desbordamiento de enteros Vs. truncamiento/redondeo

Jueves, 26 de Julio de 2007

En Kriptopolis hay un post interesante que abre un debate sobre si Java es o no es explotable a partir del desbordamiento de enteros. Este “efecto”, que en C se puede combinar con otros para romper una aplicación, en Java se convierte en un truncamiento documentado del valor que supuestamente se desborda.
Está bien leer el artículo entero (y el original también en h4ck1t) y además los comentarios.

Personalmente creo que no es explotable. El caso solo se produce cuando necesitamos parsear un valor y utilizamos el método incorrecto.

Produce truncamiento:

short importe = Integer.valueOf(args[1]).shortValue();

No produce truncamiento (lanza excepcion si lo encuentra):

short importe = Short.valueOf(args[1]).shortValue();

Si necesitas un short ¿que sistema de parseado utilizarías? El segundo, ya que se apoya en el objeto wraper de short, que es java.lang.Short, el cual si lanza un NumberFormatException si el valor no “cabe” en un short (entre -32768 y 32767).

Corta y pega código con estilo

Lunes, 7 de Mayo de 2007

Hay veces que tenemos que copiar y pegar, pero parece que Java nos pone trabas a ellos cuando resulta demasiado evidente.
Por ejemplo, supongamos este método de una clase ficticia:

public void chorrada() {
	StringBuffer sb = new StringBuffer();
	List temporal = new ArrayList();
	for (int n = 0; n<10; n++) {
		String hola = "hola";
		sb.append(n).append(hola);
		temporal.add(sb);
	}
}

Un código absurdo, pero eso no importa. Ahora coge este código, cópialo y pégalo tres veces seguidas, así:

public void chorrada() {
	StringBuffer sb = new StringBuffer();
	List temporal = new ArrayList();
	for (int n = 0; n<10; n++) {
		String hola = "hola";
		sb.append(n).append(hola);
		sb.append(n);
		temporal.add(sb);
	}
	StringBuffer sb = new StringBuffer();
	List temporal = new ArrayList();
	for (int n = 0; n<10; n++) {
		String hola = "hola";
		sb.append(n).append(hola);
		temporal.add(sb);
	}
	StringBuffer sb = new StringBuffer();
	List temporal = new ArrayList();
	for (int n = 0; n<10; n++) {
		String hola = "hola";
		sb.append(n).append(hola);
		temporal.add(sb);
	}
}

Si tienes un IDE moderno o compilas, verás que la segunda y tercera declaración de las variables sb y temporal fallan: “Variable sb is already define in the scope”, que viene a significar como que la variable ya está definida en el ámbito actual. ¿Y cuál es ese ámbito? El código del método, pero ¿porqué? pues porque está cerrado entre sus propias llaves {}. Fíjate que la variable hola está definida también tres veces, pero no falla al compilar. Eso es porqué su ámbito son las llaves {} del bucle for.
Bueno, una manera de evitar esto es añadirle unas llaves a nuestro código, sin más. Así:

public void chorrada() {
	{
		StringBuffer sb = new StringBuffer();
		List temporal = new ArrayList();
		for (int n = 0; n<10; n++) {
			String hola = "hola";
			sb.append(n).append(hola);
			sb.append(n);
			temporal.add(sb);
		}
	}
	{
		StringBuffer sb = new StringBuffer();
		List temporal = new ArrayList();
		for (int n = 0; n<10; n++) {
			String hola = "hola";
			sb.append(n).append(hola);
			sb.append(n);
			temporal.add(sb);
		}
	}
	{
		StringBuffer sb = new StringBuffer();
		List temporal = new ArrayList();
		for (int n = 0; n<10; n++) {
			String hola = "hola";
			sb.append(n).append(hola);
			sb.append(n);
			temporal.add(sb);
		}
	}
}

Ahora cada fragmento tiene su propio ámbito, podemos definir cuantas variables que queramos dentro, que una vez finalice este ámbito definido por sus propias llaves {}, las variables desaparecerán.
Así conseguiremos copiar y pegar con estilo, sin cambios, digno de un buen código spaghetti listo para sembrar el pánico, así que usar con precaución e intentar evitarlo… pero si no hay más remedio…

Diferencias y similutes entre C# y Java

Sábado, 5 de Mayo de 2007

He encontrado en Javahispano un enlace a un artículo muy bueno donde explica con ejemplos de código, todas y cada una de las diferencias y similitudes entre C# y Java. Es un artículo ideal si conoces Java y te vas a meter a programar en C#. Puede que te ahorres unos cuantos tutoriales.

C# From a Java Developer’s Perspective