Software Reaccionario - por fschmidt

Tutorial de BeanShell Reaccionario


Contenido


Introducción

contenido

BeanShell es un lenguaje de scripting basado en Java que se parece mucho a Java. Es mucho más amigable para principiantes que Java. Si aprendes BeanShell, aprender Java será mucho más fácil.

Ejecutando BeanShell

contenido

Descarga bsh-xx.jar y colócalo en tu directorio de trabajo.

~/beanshell $ ls -F bsh-2.0b4.jar bsh_console.sh* ~/beanshell $ cat bsh_console.sh #!/bin/bash export CLASSPATH=bsh-2.0b4.jar java bsh.Console & ~/beanshell $

Copia mi bsh_console.sh en tu directorio de trabajo. Un archivo jar contiene código Java compilado. El CLASSPATH le dice al comando java dónde encontrar el código Java compilado.

Ahora puedes ejecutar BeanShell:

~/beanshell $ ./bsh_console.sh ~/beanshell $

Deberías ver una nueva ventana que te permite interactuar con BeanShell. De ahora en adelante, me referiré principalmente a las interacciones en esa ventana.

Comenzando

contenido

Desde la ventana:

bsh % pwd(); /Users/fschmidt/beanshell bsh % print("Hello world!"); Hello world! bsh % print(1+1); 2 bsh %

El comando pwd de BeanShell es como el comando pwd de Bash, y el comando print de BeanShell es algo parecido al comando echo de Bash. Pero la sintaxis es diferente. BeanShell y Java tienen una sintaxis como la mayoría de los lenguajes de programación. Mientras que Bash hace command arg1 arg2 arg3, la mayoría de los lenguajes de programación hacen command(arg1,arg2,arg3). Además, Java requiere un ; al final de una sentencia (línea de comando).

pwd y print son solo comandos de BeanShell. No están en Java.

También nota que Java tiene los operadores aritméticos estándar.

Variables

contenido
bsh % String message = "Hello world!"; bsh % print(message); Hello world! bsh % int i = 2; bsh % print(i); 2 bsh % print(i+1); 3 bsh % i = i + 5; bsh % print(i); 7 bsh %

Las variables contienen valores. En Java (pero no en BeanShell), las variables deben ser declaradas con un tipo. El tipo String es para texto, y int es para enteros.

El comando = asigna un valor a una variable.

Objetos y Cadenas

contenido
bsh % print( message.toUpperCase() ); HELLO WORLD! bsh % print( message.length() ); 12 bsh % print( message.getClass() ); class java.lang.String bsh %

Java es un lenguaje orientado a objetos, lo que significa que trata principalmente con objetos. Explicaré con ejemplos del mundo real. Para mostrar un perro o una tostadora, haría algo como show(dog) o show(toaster). Mostrar es algo que hago a estos objetos, no está incorporado en los objetos. En contraste, para hacer que un perro corra haría dog.run(), y para hacer que una tostadora tueste pan haría toaster.toast(bread). Correr es una función incorporada en los perros, mientras que tostar está incorporado en las tostadoras. Las funciones que están incorporadas en los objetos se llaman "funciones miembro".

Pero en realidad esto va más allá. Los perros son un tipo de canino y todos los caninos pueden correr. Así que la habilidad de los perros para correr en realidad proviene de ser caninos. En Java, llamaríamos a los perros, caninos y tostadoras "clases", y diríamos que los perros son una subclase de los caninos, y que los caninos son una superclase de los perros.

Volviendo a la programación. La clase de message (una String) es java.lang.String. Haz clic en ese enlace y verás todas las cosas que las cadenas pueden hacer. Por ejemplo, pueden toUpperCase y length. Estas funciones devuelven valores. Las cadenas también pueden getClass pero esta funcionalidad proviene de la superclase java.lang.Object. Los objetos son la clase base de todo. Mira de nuevo en la parte superior de java.lang.String y verás la jerarquía de clases y verás que String es una subclase de Object.

Interfaces y Listas

contenido
bsh % List list = new ArrayList(); bsh % print( list ); [] bsh % print( list.size() ); 0 bsh % list.add("a"); bsh % print( list ); [a] bsh % print( list.size() ); 1 bsh % list.add("b"); bsh % list.add("c"); bsh % print( list ); [a, b, c] bsh % print( list.size() ); 3 bsh % print( list.get(0) ); a bsh % print( list.get(1) ); b bsh % print( list.getClass() ); class java.util.ArrayList bsh %

java.util.ArrayList es una clase. Para hacer un nuevo objeto de una clase, usamos el operador new. Si miras en la parte superior de la página de ArrayList, verás "Todas las Interfaces Implementadas:" que incluye "List" y haciendo clic en eso te lleva a java.util.List. List es una interfaz que puedes pensar como una clase puramente abstracta. Una interfaz solo especifica lo que hace un objeto, no cómo. Una clase concreta como ArrayList especifica cómo los objetos hacen lo que hacen (la implementación) para que el objeto pueda realmente hacer estas acciones. Nota que una interfaz puede ser implementada/subclaseada por múltiples clases que implementan la interfaz de diferentes maneras. Puedes ver esto en java.util.List bajo "Todas las Clases que Implementan Conocidas:".

Nota que el primer índice de una lista es 0 no 1. Así que el último índice de una lista es list.size() - 1.

Java organiza las clases en paquetes. El paquete de List y ArrayList es java.util. Está lleno de clases útiles. Java tiene un gran número de clases estándar, y no voy a repasar más clases de las necesarias para transmitir los conceptos básicos de Java. Puedes aprender las clases que necesitas por tu cuenta.

Valores Booleanos e Igualdad

contenido
bsh % print( 3 > 4 ); false bsh % print( 3 >= 4 ); false bsh % print( 3 < 4 ); true bsh % print( 3 <= 4 ); true bsh % print( 3 == 4 ); false bsh % print( 3 != 4 ); true bsh % print( 3 < 4 && 3 > 4 ); false bsh % print( 3 < 4 || 3 > 4 ); true bsh % boolean b = 3 < 4; bsh % print(b); true bsh % print( b == true ); true bsh %

== verifica la igualdad, != verifica la desigualdad, && es para "y", y || es para "o". Estos son operadores booleanos que devuelven valores booleanos, a diferencia de algo como + que es un operador aritmético. boolean es un tipo que puede tener los valores true o false.

bsh % String s1 = new String("hi"); bsh % String s2 = new String("hi"); bsh % print( s1 == s2 ); false bsh % print( s1.equals(s2) ); true bsh % String s3 = s1; bsh % print( s1 == s3 ); true bsh %

Si tienes dos objetos en el mundo físico que son idénticos, entonces no son el mismo objeto pero son objetos equivalentes. En Java, object1 == object2 verifica si object1 y object2 se refieren al mismo objeto. Las variables de objeto se refieren a objetos, no contienen el valor del objeto. object1.equals(object2) verifica la equivalencia de objetos.

Los tipos int y boolean son tipos primitivos. No son objetos. Las variables de tipo primitivo contienen valores primitivos, por lo que no se refieren a nada. Así que en este caso, == verifica valores iguales.

Ejecutar Archivo y Comentario

contenido

Ahora volveré a la línea de comandos de Bash.

~/beanshell $ ls -F bsh-2.0b4.jar bsh.sh* bsh_console.sh* code.bsh ~/beanshell $ cat bsh.sh #!/bin/bash export CLASSPATH=bsh-2.0b4.jar java bsh.Interpreter $* ~/beanshell $ cat code.bsh /* Esto es un comentario */ // Esto también es un comentario print("Hi"); print("Bye"); ~/beanshell $ ./bsh.sh code.bsh Hi Bye ~/beanshell $

bsh.sh ejecuta un archivo BeanShell desde la línea de comandos. Seguiré modificando code.bsh para mostrar mis ejemplos.

En Java, los comentarios están entre /* y */ o entre // y el final de la línea. Los comentarios son ignorados.

Sentencias If

contenido
~/beanshell $ cat code.bsh int x = 5; print("primer if"); if( x == 5 ) { print("x == 5"); } print("segundo if"); if( x > 5 ) { print("x > 5"); } else { print("x <= 5"); } print("tercer if"); if( x > 5 ) { print("x > 5"); } else if( x < 5 ) { print("x < 5"); } else { print("x == 5"); } ~/beanshell $ ./bsh.sh code.bsh primer if x == 5 segundo if x <= 5 tercer if x == 5 ~/beanshell $

Las sentencias if toman un argumento booleano.

Bucles

contenido
~/beanshell $ cat code.bsh ~/beanshell $ cat code.bsh print("primer bucle"); int i = 1; while( i <= 3 ) { print(i); i = i + 1; } print("segundo bucle"); for( int i = 1; i <= 3; i = i + 1 ) { print(i); } List list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); print("tercer bucle"); for( int i = 0; i < list.size(); i = i + 1 ) { String s = list.get(i); print(s); } print("cuarto bucle"); Iterator iter = list.iterator(); while( iter.hasNext() ) { String s = iter.next(); print(s); } print("quinto bucle"); for( String s : list ) { print(s); } ~/beanshell $ ./bsh.sh code.bsh primer bucle 1 2 3 segundo bucle 1 2 3 tercer bucle a b c cuarto bucle a b c quinto bucle a b c ~/beanshell $

La primera forma del bucle for tiene tres elementos: una declaración de inicialización, una condición de bucle y una declaración que se ejecuta después de cada iteración del bucle. La segunda forma del bucle for itera a través de cualquier cosa que sea iterable, devolviendo valores en secuencia. Para el cuarto bucle, ver List.iterator().

Bloques

contenido
~/beanshell $ cat code.bsh { String s = "ok"; print( "primero " + s ); } print( "segundo " + s ); ~/beanshell $ ./bsh.sh code.bsh primero ok segundo void ~/beanshell $

El código entre las llaves { y } es un bloque. Cuando las llaves son parte de una sentencia como una sentencia for, el bloque se extiende para incluir toda la sentencia. Las variables declaradas dentro de un bloque solo existen dentro de ese bloque.

En BeanShell una variable indefinida es void pero en Java obtendrías un error de compilación.

Nota que además de ser un operador aritmético, + también concatena cadenas.

Arreglos y null

contenido
~/beanshell $ cat code.bsh String[] array = { "a", "b", "c", "d", "e" }; print( "array = " + Arrays.asList(array) ); print( "length = " + array.length ); print( "array[1] = " + array[1] ); array[1] = "bb"; print( "modified array = " + Arrays.asList(array) ); print("bucle"); for( String s : array ) { print(s); } array = new String[3]; print( "new array = " + Arrays.asList(array) ); array[2] = "two"; print( "modified new array = " + Arrays.asList(array) ); ~/beanshell $ ./bsh.sh code.bsh array = [a, b, c, d, e] length = 5 array[1] = b modified array = [a, bb, c, d, e] bucle a bb c d e new array = [null, null, null] modified new array = [null, null, two] ~/beanshell $

Los arreglos son una anomalía: ni tipo primitivo ni objeto. Los arreglos no hacen nada que las listas no puedan hacer. La razón por la que Java tiene arreglos es porque los arreglos son un concepto de programación de bajo nivel fundamental, y Java es un lenguaje de bajo nivel.

Los arreglos se declaran con el tipo que contendrán, y luego solo pueden contener ese tipo. Los arreglos no pueden cambiar de tamaño.

Como los arreglos no saben cómo convertirse en cadenas, usé Arrays.asList() que convierte un arreglo en una lista para que pueda mostrarse correctamente. Nota que esta es una función static lo que significa que no es parte de un objeto, sino que es una función general que está asociada con una clase.

En la segunda parte del código, asigno array a un nuevo arreglo de longitud 3 sin valores. Java usa el valor especial null para significar sin valor.

Funciones

contenido
~/beanshell $ cat code.bsh int add(int x,int y) { return x + y; } void addAndShow(int x,int y) { int sum = x + y; print( x + " + " + y + " = " + sum ); } void sayBye() { print("Bye"); } print( "add(2,3) = " + add(2,3) ); addAndShow(2,3); sayBye(); ~/beanshell $ ./bsh.sh code.bsh add(2,3) = 5 2 + 3 = 5 Bye ~/beanshell $

Las funciones hacen posible el código reutilizable, y son el concepto central de la programación. En Java, las definiciones de funciones comienzan con el tipo de retorno, luego el nombre de la función, luego los parámetros de la función con tipos, y luego un bloque que implementa la función. Un tipo de retorno de void significa que no se devuelve nada.

Implementando Interfaces

contenido
~/beanshell $ cat code.bsh Iterator iter = new Iterator() { int i = 0; boolean hasNext() { return i < 10; } int next() { i = i + 1; return i; } }; while( iter.hasNext() ) { print( iter.next() ); } ~/beanshell $ ./bsh.sh code.bsh 1 2 3 4 5 6 7 8 9 10 ~/beanshell $

BeanShell no te permite implementar nuevas clases, debes usar Java para eso. Pero BeanShell te permite implementar interfaces, lo cual es similar a implementar una nueva clase. En este caso, implemento Iterator que define dos funciones miembro que deben ser implementadas. Típicamente una implementación incluirá tanto funciones miembro como datos/variables miembro. Los datos miembro describen el estado del objeto, y las funciones miembro a menudo modifican ese estado. Este iterador cuenta de 1 a 10, y la variable miembro i lleva el registro del conteo actual.

Este ejemplo es solo para dar una idea de la programación orientada a objetos. Cuando aprendas Java, aprenderás mucho más sobre esto.

Conclusión

contenido

El propósito de este tutorial es introducir conceptos básicos de Java que harán que aprender Java sea más fácil. Evité detalles y ejemplos complicados.

Cuando estés aprendiendo Java, todavía creo que BeanShell es una herramienta útil para la experimentación. Puedes probar rápidamente cosas en BeanShell que tomarían más tiempo probar en Java.