Programación Funcional
Principios funcionales en Java
Java 8
- Funciones como datos: Lambdas y closures
- Streams
- Referencias simplificadas
- Optional
Lambdas y closures
Arrays.asList( "a", "b", "d" ).forEach(
e -> System.out.println( e )
);
Arrays.asList( "a", "b", "d" ).forEach(
String e -> System.out.println( e )
);
Arrays.asList( "a", "b", "d" ).sort(
( e1, e2 ) -> e1.compareTo( e2 )
);
Lambdas y closures
interface TxAction{ void execute(); }
void update(TxAction action){
tx.begin();
try{
action.execute();
}finally{
tx.commit();
}
tx.dispose();
}
void paySomething(){
update( () -> {
user.updatePayment();
user.updateDebt();
});
}
Streams
int openTasksPoints = tasks.stream()
.filter( task -> task.getStatus() == Status.OPEN )
.mapToInt( task -> task.getPoints() )
.sum();
Referencias simplificadas
int openTasksPoints = tasks.stream()
.filter( task -> task.getStatus() == Status.OPEN )
.mapToInt( Task::getPoints )
.sum();
Un simple problema
Programming Pearls Magazine, 1986
"Leer un archivo de texto, determinar la cantidad de palabras mas usadas, e imprimir una lista ordenada alfabéticamente de estas palabras junto con sus frecuencias."
Clonar su repositorio desde http://20.20.:8000/ (mercurial)
Hacer correr las pruebas
Verificado por la integración continua
Tienen 40 mins
Algunas reglas
No usar asignaciones
No usar NULLs
Resultado funcional
public String countWords(File file) {
return readLines(file)
.stream()
.map(line -> line.split("[\\W]"))
.flatMap(Arrays::stream)
.filter(word -> !word.isEmpty())
.collect(Collectors.groupingBy(
word -> word, Collectors.counting())
)
.entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.collect(Collectors.toList()).toString();
}
Cuál es la diferencia?
Qué tienes en tu caja de herramientas?
- Lenguajes de programación
- Frameworks y librerías
- Plataformas y protocolos
Qué realmente tienes en tu caja de herramientas?
Programación procedimental
Orientada a objetos
Orientada a aspectos
Funcional
Lógica
Simplicidad
El arte de la programación es el arte de organizar complejidad, de controlar el desorden y evitar el caos de la forma mas efectiva posible.Edsger W. Dijkstra
Simple != Fácil
Por qué nos debería importar?
Los programas complejos tienen mas bugs
Los programas complejos son mas difíciles de cambiar
Los programas complejos son menos legibles
Los programas complejos son menos flexibles
Programación funcional
La programación funcional es un estilo de programación que enfatiza la evaluación de expresiones por encima de la ejecución de comandoscom.lang.functional, 2014
Una función es la relación entre valores donde un valor de entrada retorna exactamente un valor de salida.comp.lang.functional, 2014
Algunas funciones
- Math.sqrt(x)
- Collections.max(x)
- Arrays.asList(x...)
- String.valueOf(x)
Principios de programación funcional
Principios
- Flujo de datos
- Inmutabilidad
- Estilo declarativo
- Datos como datos
Flujo de datos
String readAsString(InputStream stream) throw IOException{
val reader = new InputStreamReader(stream);
return CharStreams.toString(reader);
}
List<String> readAsLines(InputStream stream) throw IOException{
return IOUtils.readLines(stream);
}
void main(){
val input = new FileInputStream("myfile.txt");
println("content: " + readAsString(input));
println("lines: " + readAsLines(input));
}
Exception!!!!
String readAsString(InputStream stream) throw IOException{
val reader = new InputStreamReader(cloneOf(stream));
return Streams.toString(reader);
}
List<String> readAsLines(InputStream stream) throw IOException{
return IOUtils.readLines(cloneOf(stream));
}
InputStream cloneOf(InputStream input){
val cloned ....
return cloned;
}
No tocar el estado global
No modificar datos de entrada
No interrumpir el flujo de ejecución
No usar NULL
Alcance local
Determinístico
Baja complejidad
No interrumpe el flujo de ejecución
Inmutabilidad
El problema que tenemos es que por años hemos enseñado efectivamente a generaciones de programadores que el estado mutable nos permite trabajar de la mejor forma. Ahora estamos en una carrera para enseñar que no todo eso es ciertoAnders Hejlsberg, SEI-Radio, 2008
Valores < - > Tiempo
Git / Mercurial / Fossil
Acoplamiento temporal
Request req = new Request("http://juanbandafanpage.com"); req.method(Request.POST); request.body("fanId=chichico"); request.fetch();Request req = new Request("http://juanbandafanpage.com"); // req.method(Request.POST); request.body("fanId=chichico"); request.fetch(); //NPE!!!
Acoplamiento temporal
Request req = new Request("http://juanbandafanpage.com"); req = req.body("fanId=chichico"); req = req.post(); req.fetch();Request req = new Request("http://juanbandafanpage.com"); req.body("fanId=chichico").post().fetch();
- java.lang.String
- java.util.Date
- com.google.guava
Todo valor es inmutable por defecto
Todo valor modificado, genera un nuevo valor
Los estados mutables son privados/locales
Los valores no cambian, generan nuevos valores
Los valores no necesitan thread-safety
No existen efectos secundarios
Identidad!!!
Estilo declarativo
Diga lo que hace, haga lo que dice
int countBugs(String filePath){
Path path = Paths.get(filePath);
int count = 0;
try(FileReader reader = new FileReader(
Files.newInputStream(path))
){
String line = null;
while( (line = reader.readLine()) != null )
if(line.contains(“BUG”))
count++;
}catch(IOException e){
printErr(e);
}
}
int countBugs(String filePath){
return Files.readAllLines(Paths.get(filePath))
.stream()
.filter(line -> line.contains(“BUG”))
.count();
}
Mas ejemplos?
List<Deposit> deposits= …;
// give me the big transfers
long allBigTransfers = deposits.stream()
.filter(d -> d.amount > 10000L)
.mapToLong(d -> t.amount)
.sum();
// give me the smallest transfer
Optional<> minTransfer = deposits.stream()
.min((d1, d2) -> d1 > d2);
Enfocarse en el qué, no en el cómo
Abstraer infraestructura
Generar expresiones, y no órdenes
Código expresivo/legible
Enfoque en el fondo, no la forma
Simplicidad inherente
Evaluación optimizable
Datos como datos
HttpServletRequest
getAsyncContext,getAttribute, getAttributeNames,
getCharacterEncoding,getLength,getContentLength,
getType,getContentType,getDispatcherType,getLocalName,
getLocalAddr,getLocale,getLocales,getLocalName,
getLocalPort,getParameterNames,getParameterValues,
getProtocol,getReader,getRealPath,getRemoteAddr,
getRemoteHost,getRemotePort,getRequestDispatcher,
getScheme,getServerName,getServerPort,isSecure,
removeAttribute,setAttribute,setCharacterEncoding,
startAsync,getHeader,getHeaderNames,getIntHeader,
getResponseStream,
...
[
"remote-addr": "127.0.0.1",
"scheme": "http",
"form-params": [],
"query-string": "fanId=chichico",
"request-method": "GET",
"content-type": "text/csv",
"server-name": "localhost",
"params": ["key": "value"],
"server-port": 8080,
"headers": [
"accept-encoding" : "gzip, deflate",
"connection": "close",
"content-length": 0,
...
]
]
class CustomerId{
private int id;
private String value;
//.....
}
class InValue{
private int id;
private String value;
private int type;
//...
}
class OutValue{
//...
}
class InValueContainer{
//...
}
class OutValueContainer{
//...
}
Efectos
Inconsistencia
Duplicidad
Acoplamiento
La especificidad esta sobre-valorada
Primitives
Lists
Sets
Dictionary
Usar primitivos hasta donde se pueda
Usar estructuras hasta donde se pueda
Evitar los objetos anémicos
Evitar estructuras hereditarias
Datos expresivos y claros
Uniformidad y simplicidad de código
Re-utilización
JSON...
Finalmente
La simplicidad es la característica mas devaluada de los sistemas de software.Yo, hace 10 segs
Muchas gracias!
functional programming
By Timoteo Ponce
functional programming
- 591