lunes, 12 de diciembre de 2016

Angular 2. Entrega 4 Elementos básicos de Angular 2. Componentes

Veamos los elementos básicos de Angular 2

1. Componentes. Introducción

Un componente permite crear una nueva etiqueta html y se define su comportamiento. Analicemos el app.component.ts


import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
}

Destaquemos lo siguiente:
1. import. Siempre debemos indicar las dependencias. En este caso @Component está definida en angular.core.
2. selector: Es la nueva etiqueta html que creamos
3. templateUrl: Puede ser tanto una url donde está nuestro código ( fichero o plantilla)  html, o simplemente se puede indicar código html. Si está en la misma línea, podemos indicar las comillas simples ('') para separar el código html. En caso de haber varias líneas se debe separar mediante acentos graves (``).
4. styleUrls: Se pueden indicar un array con varios ficheros de css.
5. export : para hacerla pública la clase.
6. lógica de clase: en este caso asignamos una variable (title).
7. Localización de los ficheros: en este caso se usa "./" para indicar que están en la misma capeta (rutas relativas).

Veamos como referenciamos este componente en la aplicación

si vamos al fichero index.html , veremos que hay una referencia a este componente:


<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>Ejem01</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

vemos que en body hay una etiqueta <app-root>Loading...</app-root> que es la que nos mete el código html que se genera en el componete anterior.


2. Modificación del codigo html en el componente.

Vamos a modificar el código del componente y le vamos a suministrar código html sin necesidad de tenerlo en un fichero a parte. Micael aporta este código dentre de "templateUrl", pero nosotros como somos mas "gafes" solamente nos funciona con "template", por eso hemos comentado "templateUrl".
Para que el código acepte varias líneas tenemos que usar las comillas del acento grave, o como dice Micael "comillas chungas". Estas comillas también permiten la sustitución de variables.

Veamos como quedaria.

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  //templateUrl: './app.component.html',
  template: `
    <h1>
      a ver si va este codigo angular 2
    </h1>
    `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app works!';
}

Le damos a salvar Ctrl+S y acontinuación Angular CLI recompila y el navegador nos ofrece la nueva vista.


3. Acceso a variables desde el fichero html

Veamos otra versión del copmponente anterior que referencia al fichero html y le creamos 2 variables, siendo la última la dirección de una imagen que hemos guardado en el directorio de recursos "assets".

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  styleUrls: ['./app.component.css'],
  templateUrl: './app.component.html',
})
export class AppComponent {
  title = 'app works, my folk, hehe!';
  imgUrl= "assets/llissa.jpg";
  myName = 'Ximo Dante';

  setMyName (myName: string) {
     this.myName=myName;
  }
}




Respecto al fichero app.copmponent.html cuyo código es:

<h2>Título:</h2>
<h1> {{title}} </h1>
<img [src]="imgUrl" />

mi nombre es {{myName}}
  
<button (click) = "setMyName('John Travolta')" > Hola John </button>


Y destacamos:

1. Para incluir una variable dentro del texto utilizamos la sintaxis "moustache" es decir las dobles llaves. En este caso usamos la variable title definida en AppComponent, y se expresa {{title}}.

2. Para los atributos de html, dentro de los elementos html "<>", colocamos el atributo entre corchetes (en este caso [src]) y el valor de dicho atributo o sea el nombre de la variable, entre comillas dobles , en este caso "imgUrl".

3. Creamos un método tipo "setter" para establecer la variable "myName" y lo ejecutamos con un botón para cambiar el nombre inicial. El hml es capaz de asociar este método al click del botón en el html. Para ello hemos indicado el método "click" entre paréntesis.

4. Por tanto no hay que confundir los corchetes "[]" que se asocian a atributos ( <img [src]="imgUrl" />), con los paréntesis "()" que se asocian a las acciones (<button (click)= "set MyName('John')" ... )



jueves, 8 de diciembre de 2016

Angular 2. Entrega 3. Empezando con Angular. Creando el esqueleto con angular-cli

1. Construcción de código esqueleto.

Podemos utilizar :
1,Yeoman que es un generador de esqueleto de programación para cualquier lenguaje. Hay muchos generadores yeoman, y hay que comprobar que esten actualizados
2. Proyectos semilla (seed) de github. También hay muchos, y hay que verificar que esten al dia
3. Herramienta oficial Angular CLI.

Para instalar Angular CLI, parece ser que requiere npm version 3 o posterior, Si estamos trabajando con windows, seguramente Nodej no instaló las últimas versiones de npm, por tanto, hay que ejecutar PowerShell como administrador y desde ahí actualizar con estos comados:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
npm install --global --production npm-windows-upgrade
npm-windows-upgrade

Ahora ya podemos instalar Angular CLI. Para ello ejecutamos (siempre que se pueda en modo sudo en ubuntu, o en modo administador en windows:

sudo npm install -g angular-cli

Ahora creamos un nuevo proyecto llamado ejem01

sudo ng new ejem01

Y esperamos a que cargue 150 MB de internet.

En modo administrador ejecutamos

sudo ng serve

y esperamos bastante tiempo y al final vamos al navegador y en localhost:4200 aparece


Abrimos con Atom la carpeta elem01. Y vemos:

1. e2e: carpeta de testing end to end.
2. tslint.json configuracion del lint de js para el tema de calidad de código.
3. src: carpeta con código de la aplicación.
4. README.md archivo de formato ligero mark-down para llevarlo a github.
5. karma.conf.js para configuración de testing
6. angular-cli.json: configuración de la propia herramienta.
7. package.jon: configuración del npm, definiendo dependencias
8. node-modules: carpeta con libreria y herramientas descargadas. Micael propone trasladarla al directorio padre para que pueda ser utilizada en todos los ej ca recursivamente hacia arriba. Ojo si hacemos esto habrá que hacer el npm install.

Hay que tener precaución para configurar los IDEs para ue cojan la version 2 de typescript. Para ello Micael buscaba en google "vscode typescript new version", siendo vscode el editor que el utilizaba.

Para publicar en producción hacemos:

ng build

que genera los ficheros en la carpeta dist. Estan planeando optimizar el codigo generado, pero de momento el resultado (main.bundle.js) ocupa 2,5 MB. Si buscas en google "tree shaking in angular 2" se pueden ver técnicas que reducen el código mediante la eliminación de los componentes no usados.

2. Configuración de Atom

Siguiendo las instrucciones de nuestro amigo Micael Gallego,  en su diapositiva 68/257 vamos a decirle a Atom que no genere los ficheros javaScript ya que los genera Angular-CLI.


{
  "compilerOptions": {
    "baseUrl": "",
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": ["es6", "dom"],
    "mapRoot": "./",
    "module": "es6",
    "moduleResolution": "node",
    "outDir": "../dist/out-tsc",
    "sourceMap": true,
    "target": "es5",
    "typeRoots": [
      "../node_modules/@types"
    ]
  },
  "compileOnSave":false
}


Para ello, añadimos "compileOnSave":false al final del fichero tsconfig.json  

Angular 2. Entrega 2. Un poco de Typerscript

1. Características generales de Typescript


Se aconseja trabajar con Typescript que es un javascript tipado que nos ayuda a disminuir los errores inesperados de ejecucion. ya que permite:
1. Inferencia de tipos
2. Tipos opcionales
3. Orientación a objetos y clases
4. Anotaciones (decorators)

2. Clases en Typescript


1. Una clase pública se indica con export class NombreClase
2. Un constructor se define como constructor( parametros)
3. Los atributos de clase ( y también los métodos) son publicos y se aconseja declarar su tipo, en caso que fueran privados se indicaría public atributo1: string
4. Los métodos no hace falta declarar el tipo ya que se infieren por el tipo de variable que devuelven.
5. Cuando se referencia a un atributo dentro de la clase, hay que hacerlo con this.atributo.
6. Lo normal es guardar cada clase en su propio fichero, en este caso Persona.ts
7. Si queremos usar esa clase, habrá que importarla tal y como hacíamos en Java, pero declarando dicha importación incluso si estamos en el mismo paquete o carpeta.
8. Cuando asignamos objetos se utiliza let (let objeto1=objeto2)


public class Persona {
  private nombre: string;
  private edad: number;

  constructor ( nombre:string, edad:number) {
    this.nombre=nombre;
    this.edad=edad;
  }

  getedad() {
    return this.edad;
  }

  tostring() {
    return "Persona con nombre=" + this.nombre;
 }
}

9. Mediante el constructor podemos obviar la declaración de atributos, quedando la clase anterior:

public class Persona {
  
  constructor ( private nombre:string, private edad:number) {
  }

  getedad() {
    return this.edad;
  }

  tostring() {
    return "Persona con nombre=" + this.nombre;
 }
}


Ahora si hacemos referencia a ella desde otro fichero en el mismo directorio:

import { Persona } from "./Persona"

personas = new Array<Persona>();

3. Arrays, blucles,  arrow functions e interfaces en Typescript


1. Antes hemos visto como declar un array
2. Para añadir un elemento se utiliza push  ej. personas.push(new persona( 'Ximo', 30));
3. Hay bucles for ej. for (let pers of personas) {console.log (pers.getedad())};
4. En las lambdas (arrow functions)se utiliza el operador => (no confundir con el de java ->)
5. Las lambdas pueden acceder y modificar variables fuera de ellas (en java estasd variables son finales)
6. Desaparece el patrón this that de javascript en un lambda, y ahora solo se utiliza this

import { Persona } from "./Persona"

personas = new Array<Persona>();

personas.push (new Persona('Ximo',30));
personas.push (new Persona('Tatiana',54));

for ( let pers of personas) {
  console.log(pers.getedad());
}

personas.forEach(pers => {
  console.log(pers.getedad());
});

7. Podemos crear interfaces, para tipificar variable. 
8. Mediante ? indicamos que el atributo es opcional

interface DatosOpcionales{
  altura: number;
  peso?: number;
}
let otros: DatosOpcionales;
otros = {altura: 1.70};
otros = {altura : 1.76, peso:80);

9. Una variable declarada de un tipo puede asignarse a otro tipo de variable siempre que los atributos (y métodos) sean iguales (que tengan la misma estructura también llamada contrato).

interface Persona {
  nombre: string;
}

class Trabador {
  constructor (public nombre: string){};
}

let yo: Persona;
yo = { nombre: 'Timoteo'};
yo = new Trabajador('Ximo');

9. La sobrecarga de métodos es un poco especial, permitiendo tener parametros opcionales. Se pueden tener varias declaraciones de métodos. pero una sola implementaciòn.

4. Anotaciones (decorators) , promesa en Typescript


1. Para usar una anotación hay que importarla previamente.
2. Una anotación puede tener parejo un comportamiento.
3. Por ejemplo la anotación @Component de angular, es como una función que hay que meterle paréntesis,

4. De momento no podemos utilizar el patrón async/await ya que solo esta en ES6. Tenemos que utilizar promesas
5. variables tipo union "|"(ej. let var1; number | string)
6. Utilizaremos el operador typeof para saber el tipo de la variable en ese momento, y no hace falta hacer un "cast".


miércoles, 7 de diciembre de 2016

Angular 2. Entrega 1. Configurando el entorno de desarrollo

Vamos a intentar aprenderAngular 2, que es la moda del momento. Ja veremos si el futuro nos aconseja este camino. Para la plataforma y gestion de paquetes hace falta nodej y npm. Como empaquetadores de proyectos están: Grunt, Gulp, Webpack y Broccoli. En Angular han apostado por Webpack.

1. Elección de Atom como editor.

Elegimos Atom ya que es de software libre y no nos va acostar nada esta prueba. Para instalarlo, podemos descargarlo de su url. También podríamos utilizar Visual Studio. Pero de momento descartamos esta última opción.

2. Instalar.módulo de Typescript en Atom.

Siguiendo las indicaciones de Denis Vuika, procedemos a la pestaña de Settings y el punto donde pone Install y le indicamos atom-typescript y le damos al boton package, e install.



3. Instalar Nodej y Git


Una vez se ha instalado, hay instalar también  nodej y git, descargandolo de sus respectivos enlaces.Nodej es importante ya que tiene el instalador npm.


4. Añadir los siguientes componentes a Atom: linter, editorconfig y file-icons


Para ello ejecutamos en una sesión de terminal como administrador (si estamos en Linux, hay que prefijar el sudo):

para linter

npm install https://github.com/steelbrain/linter


npm install https://github.com/sindresorhus/atom-editorconfig


npm install https://github.com/DanBrooker/file-icons





5. Angular CLI

Ahora nos desmarcamos de Denis Vuika, y vamos a utilizar Angular CLI. Para ello, vamos a una sesion del sistema como administrador y ejecutamos (si estamos en Linux, hay que prefijar el sudo)


npm install -g angular-cli

y para ver que funciona hacemos

ng --help

6. Características de Angular 2 


Según Micael Gallego, Angular 2 tiene las siguientes funcionalidades.

1. Inyector de dependencias
2. Servicios
3. Cliente HTTP (Rest API)
4, Navegación por la app (Routers)
5. Animaciones
6. Internacionalización
7. Soportes para test unitarios y e2e
8. Libreria de componentes (Material design)
9. Renderizacion en el servidor

Y matizar que ya no existe el $scope

viernes, 2 de diciembre de 2016

Java Streams 2/2

Con las nuevas arquitecturas multinúcleo de los procesadores, si queremos que nuestros programas sean eficientes, debemos ofrecer la posibilidad de que tengan concurrencia (cuando 2 tareas corren en períodos de tiempo que se solapan) y paralelismo (cuando 2 tareas se ejecutan simultáneamente en nucleos distintos). Por tanto puede darse el caso que 2 tareas se esten ejecutando concurrentement en un mismo núcleo (fragmentadas en trocitos que se van alternando su ejecución), pero estando el segundo núcleo desaprovechado, por tanto sin paralelismo.

También se puede hablar de paralelismo de proceso y paralelismo de datos. Un ejemplo del primero puede ser un servidor de aplicaciones donde se pueden conectar varos usuarios en conexiones "http". En paralelismo de datos, un nucleo se encarga de procesar un subconjuto de datos y el otro núcleo del resto.
Cuando se crean algoritmos con paralelismo, suele suceder que son mas lentos ya que requieren recursos adicionales para repartir el trabajo entre los procesadores y luego ensamblar el resultado. Por tanto. Pero cuando el trabajo a realizar afecta una colección grande, y se dispone de un procesador con varios núcleos, la cosa cambia.

En Java 8, tenemos el "parallelStream" como version con paralelismo del "stream".

También hay funciones de paralelismo para Arrays como :

parallelPrefix : Ejecuta una función matemática sobre los elementos del array.
parallelSetAll : Actualiza los valores del array mediante un Lambda.
parallelSort : Ordena los elementos.

1. Reglas de uso del paralelismo en streams

1. El valor inicial de la funcion reduce debe ser elemento neutro. Para la suma será el "0" y para el producto el "1"

  .reduce(0, (suma, elemento) -> suma + elemento);

o
  .reduce(1, (producto, elemento) -> producto * elemento);


2. La función de combinación debe cumplir la propiedad asociativa. En nuestro caso anterior se verifica tanto para la suma como para el producto.

  (1 + 3) + 5 = 1 + (3 + 5) = 9

  (1 * 3) * 5 = 1 *  (3 * 5) = 15

3. Cuando en un se evalua un "stream pipeline", solamente puede haber un modo, o parelelo o secuencial y no los dos a la vez. Si huebiera llamadas tanto secuenciales como paralelas, todo se ejecuta secuencialmente.


jueves, 1 de diciembre de 2016

Java 8 Streams 1/2

Hay que ver lo que nos calentamos la cabeza para llamar de otra forma los procesos repetitivos:

  • bucles (for, while, do, if, ....)
  • Iterators, colecciones ...
Ahora aparecen los Stream que no hay que confundir con los IOStream de java.

No voy a acosonsejar ni desaconsejar su uso, sino que me voy de "safari fotográfico" a conocer las nuevas especies que han entrado en el nicho ecológico de Java.

1. Ideas básicas


Parece ser que un stream es como el operador "|" (pipe) de los scripts de linux, donde la información se genera y se transforma, filtra etc y obtenemos algo.

1. El origen de los streams parece ser que es una colección, como por ejemplo un List<>.
2. Para trasformar una colección en un stream le aplicaremos el método stream.
3. Existen unos métodos que se aplican al stream que son de tipo eager que se ejecutan inmediatamente.
4. En cambio los métodos de tipo lazy no se ejecutan si tras ellos no llamos a un método eager.
5. Si un método devuelve un stream entonces es lazy.
6. Si un método devuelve un valor o nada (void), entonces es eager.

2. Operaciones básicas de los streams

collect(toList()) (Eager) Trasforma un stream en un List<>, si quisieramos transformarlo en un Set<> (que descarta los duplicados) sería collect(toSet()), y mas genericamente

List<String> collected = 
  Stream.of("a", "b", "c") 
  .collect(Collectors.toList()); 

y para comprobar que el resultado es correcto:
     
assertEquals(Arrays.asList("a", "b", "c"), collected); 

y más genericamente podriamos hacer (de momento hablaremos mas adelante del operador ::")

stream.clollect(toCollection(TreeSet::new))



map() (Lazy) Trasforma un stream en otro, realizando una "transformación" de sus elementos

List<String> collected = 
  Stream.of("a", "b", "c")
  .map(string -> string.toUpperCase())   
  .collect(Collectors.toList()); 

aquí convertimos a mayúscula los elementos y para comprobar que el resultado es correcto:
     
assertEquals(Arrays.asList("A", "B", "C"), collected); 



filter() (Lazy) Filtramos los elementos de un stream que cumplen una condición.

List<String> collected = 
  Stream.of("a", "1a", "b", "c" ,"2c")
  .filter(string -> isDigit(string.charAt(0)))   
  .collect(toList()); 

aquí solamente dejamos passar los que comienzan por un número y para comprobar que el resultado es correcto:
     
assertEquals(Arrays.asList("1a", "2c"), collected); 


flatMap() (Lazy) Cambia un objeto por un stream y lo incluye en el stream final.

List<String> collected = 
  Stream.of(asList("a", "b"), asList("c", "d"))
  .flatMap(strings -> strings.stream())   
  .collect(toList()); 

aquí solamente dejamos passar los que comienzan por un número y para comprobar que el resultado es correcto:
     
assertEquals(Arrays.asList("a", "b", "c", "d"), collected); 



max() min() (Lazy) Obiene el máximo o mínimo en base a un comparador.

String masLarga = 
  Stream.of("a", "bc","d", "efg")
  .max(Comparator.comparing(string -> strings.length()))   
  .get(); 

aquí recogemos la tira con longitud máxima y para comprobar que el resultado es correcto:
     

assertEquals("efg", masLarga); 





reduce() (Eager) Obtiene un único resultado. Puede ser la generalizacion de los métodos count, min, max ..

int sumador = 
  Stream.of( 1, 2, 3, 4)
  .reduce( 0, (suma, elemento) -> suma + elemento);
  

aquí recogemos la suma de los elementos  y para comprobar que el resultado es correcto:
     

assertEquals(10, sumador); 


4. Expresiones Lambda

Parece ser que una expresión Lambda es un tipo dado de un interface funcional, y en base a los cuales se puede inferir la función. O sea parecen 2 conceptos:

 1. Interfaz funcional : Parece ser que en Java 8 se han definido 5 interfases funcionales que son
               
InterfazArgumentosDevuelve Ejemplo
Predicate<T> T boolean Si se cumple una condición
Consumer<T> T void imprimir un valor
Function<T,R> T R Obtener el nombre de un cliente
Supplier<T> Nada T Factory method
UnaryOperator<T> T T Logical not (!)
BinaryOperator<T,T> (T, T) T Multiplicar 2 números (*)

Según TutorialsPoint, hay bastante más.

2.Inferencia: En base a como se escribe, el compilador es capaz de inferir a que tipo de interfaz funcional nos estamos refiriendo.

También aparece el concepto de Higher-Order Funtions, que es una función toma otra función como argumento o devuelve otra función. Cuando un interfaz funcional se utiliza como parámetro o como resuiltado, entonces hemos creado un función de Higher-Order (En adelante H-O). De hecho todas las funciones que se utilizan en el Stream interfaz son de H-O.

Una de las ventajas de utilizar los Lambdas es que se hace mas clara la declaración de lo que se quiere hacer.

Una cuestión a tener en cuenta es que las Lambda, solamente pueden acceder a variables externas que sean del tipo "final" o sea que no admita cambios de valor, es decir es una constante. A pesar de las desventajas que tenga esto, tiene la ventaja que no tiene efectos colaterales respecto a las variables externas que utiliza ya que no puede modificarlas.

Veamos un ejemplo donde queremos crear una función que muestre por consola si se verifica una condición:

public void mostrar(Supplier<String> mensaje) {
  if (isCondition()){
    System.out.printl(mensaje.get());
  }
}


Supongamos que este método forma parte de una clase llamada Chivato, que ademas tiene una función que construye un mensaje complejo llamada constructorMensaje. Para llamarlo, como ya podemos utilizar funciones tipo Supplier haríamos:

Chivato chivato = new Chivato();
chivato.mostrar (() -> "Mira esto:" + chivato.constructorMensaje());


5. Primitivas

Los Streams trabajan con objetos y no con primitivas. Si queremos trabajar con primitivas, tenemos dos opciones:

  1. Convertir las primitivas a objetos: Tiene la desventaja que los objetos consumen mas memoria que los primitivas
  2. Utilizar streams adaptados a primitivas.

En el segundo caso hay algunas clases y métodos que permiten trabajar con ellas. Veamos algunos de ellos:

mapToInt (): Extrae un valor entero de cada elemento de una colección de objetos. Devuelve un IntStream.

summaryStatistics (): Obtiene una clase tipo IntSummaryStatistics de un stream de primitivas tipo int.

IntSummaryStatistics (): Clase que guarda las estadísticas (max, min, promedio, suma, etc) de un stream de primitivas tipo int

Veamos un ejemplo


public static void mostrarEstaditicas (Personas personas) }
  IntSummaryStatistic est =
    personas.getEdades()
       .mapToInt( persona -> persona.getEdad())
       .summaryStatistics();

  System.out.printf("Max: %d, MIn: %d: Ave: %f, Sum %d",
    est.getMax(),
    est.getMin(),
    est.getAverage(),
    est.getSum());


Análogamente existen otras clases y métodos para LongStream y DoubleStream.


6. Referencias a métodos

Mediante la referencia a métodos  en las Lambda, se pueden hacer las siguientes equivalencias

             
             
Expresión Nueva
Expresión equivalente
Explicación
Persona::getEdad persona.getEdad() Es de la forma Classname::methodName
Persona::new (nombre, edad) -> new Persona(nombre, edad) Constructor de la clase
String[]::new Creación de un array



7. Las Null Pointer Exceptions y los Optional

La interfaz Optional se utiliza para aquellos casos que puede que el elemento no tenga un valor. Imaginemos una clase Persona que tenga de atributos nobre y teléfono. Hay personas como los niños que no tienen teléfono, por tanto este atributo se puede indicar con Otional:

public class Persona {
  private String nombre;
  private Optional<String> telefono

  public Optional<String> getTelefono() {..}
}


Veamos que ventajas tenemos, al aparecer nuevos métodos:

orElse(): Ofrece valor alternativo si no existe el valor

  String telf = persona.getTelefono().orElse("SIN TELEFONO");




orElseThrow()
: lanza una excepción si no existe el valor

  String telf = persona.getTelefono().orElseThrow(IllegalStatementException::new);


8. Otras utilidades de los streams

1. (maxBy, minBy) Obtener un objeto de entre una colección, que tenga un máximo (o mínimo). Supongamos la anterior clase Persona que tenga un atributo List<Personas> llamado hermanos, que sean los hermanos. Queremos obtener aquellas personas que tengan mayor número de hermanos. Podriamos hacerlo así

public Optional<Persona>masHermanos(Stream<Persona> personas) {
  Function<Persona, Long> getNumHermanos = persona > persona.getHermanos().count();
  return personas.collect(maxBy(comparing(getNumHermanos)));
}

igualmente existe minBy.

2.(averagingInt) Obtener el promedio de un valor de una colección.

public double promedioHermanos(List<Persona> personas) {
  return personas.stream() 
    .collect(averagingInt(persona -> persona.getHermanos.size())));
}


3.(partitioningByPartir una colección en dos en base a un criterio. Supongamos que tenemos una función isHijoUnico que indica si la persona no tiene hermanos. Podemos obtener dos listas de personas, una sin hermanos y otra que tienen hermanos.

public Map<Boolean, List<Persona>> conYSinHermanos(Stream<Persona> personas) {
  return personas.collect(partitioningBy(Persona::isHijoUnico));
}


4.(groupingBy) Agrupar varias coleccines en una sola. Supongamos que tenemos un campo en la persona que es la edad en años que es entero, y queremos agrupar todas las personas que tienen la misma edad.


public Map<int, List<Persona>> personasEdad(Stream<Persona> personas) {
  return personas.collect(groupingBy(Persona::getEdad));
}

5.(joining) Agrupar los nombres de las personas en un string separdo por comas, y de corchetes en los extremos.  Ejempo "[David, Juan, Enrique, Eduardo]" 



String
nombres

  personas.stream()
    .map(Persona::getNombre)
    .collect(Collectors.joining(", ", "[", "]"));

6.(countingObtener el numero de personas de una misma edad.

public Map<int, Long> personasEdad(Stream<Persona> personas) {
  return personas.collect(groupingBy(Persona::getEdad, counting()));


}



Resumen videos Spring Boot 101 Parte 4/4. Live Reload / Hot Swap

Como siempre damos las gracias a Dan Geabunea y su canal de videos. Finalizamos este grupo de entradas con el "Hot Swap" y "Live Reload". Veamos los pasos a seguir.

1. Añadir la dependencia "devtools" a Maven

 Tal como ya sabemos hacer metemos la dependencia:

 groupId:    org.springframework.boot
 artifactId: spring-boot-devtools

Para los que trabajan en IntelliJ, tienen que consultar el video de Geabunea para ver que hacer para que funcione bien, ya que no es evidente. En Eclipse en principio no hay problema.

Ahora hay que arrancar o rearrancar la aplicación para que los cambios de configuración se vean afectados.
Si cambiamos un fichero "html", el efecto es inmediato, pero si cambiamos una clase "java", ahí le cuesta un poco mas pero actualiza la vista en el navegador si hacemos un refresco en el mismo.

2.Live reload del navegador

Si no queremos refrescar el navegador, hay una componente que se instala en el Chrome desde la "Chrome Web Store" que se llama LiveReload, y que permite refresacar el navegador automáticamene cunado detecta un cambio.