Colecciones de Orden Superior en Java
Por: Óscar López, M.Sc.Grupo GNU/Linux de laUniversidad del Cauca
GLUC 2005 - GNU FDL
Agenda• Un ejercicio en ingeniería de lenguajes• Dos técnicas de programación
• Iteradores• Secuencias como interfaces convencionales
• Implementación en Smalltalk• ¿Y en Java, qué?
• Librería Higher Order Collections• Bloques en Java• Instanciación de colecciones• Métodos enumeradores
• Trabajo futuro• Bibliografía
GLUC 2005 - GNU FDL
Iteradores [4]
• Un patrón de diseño que permite acceder secuencialmente los elementos de un objeto agregado sin exponer su implementación interna
• Se clasifican como internos y externos, dependiendo de quién controla la iteración
• C++, Java, C# proporcionan iteradores polimórficos externos, Smalltalk dispone de iteradores internos
GLUC 2005 - GNU FDL
Ejemplo
List<Employee*>* employees;
Iterator<Employee*>* i;
i = employees->CreateIterator();
for (i.First();
!i.IsDone();
i.Next()) {
i.CurrentItem()->Print();
}
GLUC 2005 - GNU FDL
Secuencias ComoInterfaces Convencionales [3]• Definen un estilo particular para manipular
estructuras de datos• Un programa se concibe como datos
fluyendo a través de etapas de procesamiento
• Cada secuencia de datos expone una interfaz de operaciones convencionales para procesar sus elementos
• Similar en intención al patrón Visitor
GLUC 2005 - GNU FDL
Ejemplo
• Enumere las hojas de un árbol• Filtre, eligiendo las hojas impares• Calcule el cuadrado de las hojas elegidas• Acumule el valor de su sumatoria
GLUC 2005 - GNU FDL
Ejemplo
• Enumere los enteros de 0 hasta n• Calcule el número Fibonacci de cada uno• Filtre, seleccionando los pares• Acumule el resultado en una nueva lista
GLUC 2005 - GNU FDL
Ejemplo
(define (sum-odd-squares tree)(accumulate +
0(map sqr
(filter odd?(enumerate-tree tree)))))
(define (even-fibs n)(accumulate cons
‘()(filter even?
(map fibonacci(enumerate-interval 0 n)))))
GLUC 2005 - GNU FDL
Implementación en Smalltalk [5]
• Usa bloques: objetos de primera clase que encierran una función anónima y el contexto en el que ésta fue definida
• Todas las colecciones de objetos ofrecen una interfaz convencional que permite• Iterar sobre sus elementos• Realizar operaciones estándar sobre sus elementos
• Las operaciones están implementadas como funciones de orden superior que reciben un bloque como parámetro
• En Smalltalk, este conjunto de operaciones reciben el nombre de “métodos enumeradores”
GLUC 2005 - GNU FDL
Ejemplo
coll := #(1 2 3 4 5 6).
coll do: [ :e | Transcript show: e ].
coll collect: [ :e | e * e ].
coll detect: [ :e | e = 4 ].
coll select: [ :e | e < 4 ].
coll reject: [ :e | e < 4 ].
coll inject: 0 into: [ :subTotal :e | subTotal + e ].
GLUC 2005 - GNU FDL
Librería HigherOrderCollections
• Permite definir bloques en Java• Extiende las colecciones de Java,
adicionándoles métodos enumeradores como los de Smalltalk
• Disponible bajo licencia Apache 2.0 [7]• El artículo [1] profundiza en los detalles de
la implementación• El código fuente y la documentación se
pueden descargar en [2]
GLUC 2005 - GNU FDL
Librería HigherOrderCollections
Requerimientos e Instalación:
• Se debe tener instalado J2SE 1.5.0 ó superior• Incluir en el CLASSPATH el archivo higher-order-collections.jar
• Importar los siguientes paquetes:
import util.blocks.*;
import util.higherOrderCollections.*;
import static util.higherOrderCollections.HOCFactory.CollectionEnum.*;
GLUC 2005 - GNU FDL
Bloques en Java
• ¿Cómo implemento un bloque en Java?• ¿Cómo hago que sea seguro respecto a
tipos?Usando clases internas anónimas y tipos genéricos
• Existen numerosas implementaciones de bloques, se usó una versión modificada de “Blocks in Java” [6]
GLUC 2005 - GNU FDL
Bloques en Java• Procedimientos: Retornan void al evaluarlos
• Sin parámetros : ProcedureBlock• Con un parámetro (unario) : UnaryProcedureBlock• Con dos parámetros (binario) : BinaryProcedureBlock
• Predicados: Retornan un valor booleano al evaluarlos• Sin parámetros : PredicateBlock• Con un parámetro (unario) : UnaryPredicateBlock• Con dos parámetros (binario) : BinaryPredicateBlock
• Funciones: Retornan un tipo arbitrario al evaluarlos• Sin parámetros : FunctionBlock• Con un parámetro (unario) : UnaryFunctionBlock• Con dos parámetros (binario) : BinaryFunctionBlock
GLUC 2005 - GNU FDL
Ejemplo
final Integer uno = 1;
FunctionBlock<Integer> bloqueSuma;
bloqueSuma = new FunctionBlock<Integer>() {
public Integer value() {
return uno + uno; }};
bloqueSuma.value();
GLUC 2005 - GNU FDL
Instanciación de Colecciones• La forma más sencilla: usando la clase HOCFactory
HigherOrderCollection<Double> lista;
lista = HOCFactory.newInstance(LinkedList);
• HOCFactory proporciona adaptadores por defecto para las siguientes colecciones:
ArrayList, ConcurrentLinkedQueue, CopyOnWriteArrayList, CopyOnWriteArraySet, HashSet, LinkedBlockingQueue, LinkedHashSet, LinkedList, PriorityBlockingQueue, PriorityQueue, Stack, TreeSet y Vector
GLUC 2005 - GNU FDL
Instanciación de Colecciones• La forma más flexible: extendiendo la clase AbstractHigherOrderCollection
• Notar que el método getCollection()permite recuperar la colección usada internamente por la colección de orden superior:
HigherOrderCollection<Integer> col;
col = HOCFactory.newInstance(ArrayList);ArrayList<Integer> lista;lista = (ArrayList<Integer>)col.getCollection();
GLUC 2005 - GNU FDL
Métodos Enumeradores
void doBlock(UnaryProcedureBlock<E> aBlock)
Evalúa el bloque sobre cada uno de los elementos de la colección
coleccion.doBlock(new UnaryProcedureBlock<Integer>() {
public void value(Integer elemento) {
System.out.print(elemento + “ ”); }});
1 2 3 4 5 6
GLUC 2005 - GNU FDL
Métodos Enumeradores
int count(UnaryPredicateBlock<E> aBlock)
Retorna el número de elementos que al ser evaluados sobre el bloque hacen que éste retorne true
coleccion.count(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento.intValue() % 2 == 0; }});
3
GLUC 2005 - GNU FDL
Métodos Enumeradores
E detect(UnaryPredicateBlock<E> aBlock)
Retorna el primer elemento que al ser evaluado sobre el bloque hace que éste retorne true
coleccion.detect(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento == 4; }});
4
GLUC 2005 - GNU FDL
Métodos Enumeradores
E remove(UnaryPredicateBlock<E> aBlock)
Remueve de la colección y retorna el primer elemento que al ser evaluado sobre el bloque hace que éste retorne true
coleccion.remove(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento == 5; }});
5
GLUC 2005 - GNU FDL
Métodos Enumeradores
HigherOrderCollection<E>
removeAll(UnaryPredicateBlock<E> aBlock)
Remueve de la colección todos los elementos que al ser evaluados sobre el bloque hacen que éste retorne true. Retorna una nueva colección con los elementos que fueron removidos
coleccion.removeAll(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento.intValue() % 2 != 0; }});
1 3 5
GLUC 2005 - GNU FDL
Métodos Enumeradores
R inject(R thisValue,
BinaryFunctionBlock<R,E,R> binaryBlock)
Acumula y retorna el resultado de evaluar el bloque sobre cada uno de los elementos. El primer parámetro sirve como valor inicial del acumulador
coleccion.inject(0,
new BinaryFunctionBlock<Integer,Integer,Integer>() {
public Integer value(Integer acc, Integer elemento) {
return acc + elemento; }});
21
GLUC 2005 - GNU FDL
Métodos Enumeradores
HigherOrderCollection<R>
collect(UnaryFunctionBlock<E,R> aBlock)Evalúa el bloque sobre todos los elementos de la colección y va añadiendo cada valor retornado por el bloque a una nueva colección, que finalmente es retornada
coleccion.collect(
new UnaryFunctionBlock<Integer,Integer>() {
public Integer value(Integer elemento) {
return elemento * elemento; }});
1 4 9 16 25 36
GLUC 2005 - GNU FDL
Métodos Enumeradores
HigherOrderCollection<E>
select(UnaryPredicateBlock<E> aBlock)
Añade a una nueva colección los elementos que al ser evaluados sobre el bloque hacen que éste retorne true
coleccion.select(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento < 4; }});
1 2 3
GLUC 2005 - GNU FDL
Métodos Enumeradores
HigherOrderCollection<E>
reject(UnaryPredicateBlock<E> aBlock)
Añade a una nueva colección los elementos que al ser evaluados sobre el bloque hacen que éste retorne false
coleccion.reject(new UnaryPredicateBlock<Integer>() {
public boolean value(Integer elemento) {
return elemento < 4; }});
4 5 6
GLUC 2005 - GNU FDL
Trabajo Futuro
• Definir métodos enumeradores sobre las clases que implementan la interfaz Map
• Agregar nuevos métodos enumeradores• Agregar nuevos bloques que soporten un
número variable de argumentos• Proporcionar un algoritmo de iteración
más eficiente para las colecciones que implementan la interfaz RandomAccess
• Incluir un script de Ant para compilar, probar y generar la documentación
GLUC 2005 - GNU FDL
Bibliografía1. Artículo -
http://gluc.unicauca.edu.co/wiki/index.php/Colecciones_de_Orden_Superior_en_Java
2. Código Fuente -http://gluc.unicauca.edu.co/wiki/images/e/e5/Higher-order-collections.tar.bz2
3. Harold Abelson, Gerald Sussman y Julie Sussman. “Structure and Interpretation of Computer Programs”, 2da Edición. MIT Press, 1996.
4. E. Gamma, R. Helm, R. Johnson and J. Vlissides. “Design Patterns: Elements of Reusable Object Oriented Software”. Addison-Wesley, 1995.
5. Adele Goldberg, David Robson. “Smalltalk-80: The Language and Its Implementation” (El Libro Azul). Addison-Wesley, 1985.
6. Bloques en Java - http://c2.com/cgi/wiki?BlocksInJava7. Licencia Apache 2.0 - http://www.apache.org/licenses/LICENSE-
2.0
Top Related