Colecciones I

Colecciones I

Hoy vamos a ver como aprovecharnos de herramientas que nos permiten usar un código más limpio y entendible en cuanto a colecciones se refiere y para ello veremos como hacerlo en este post para colecciones con expresiones lambda y Linq de .NET con C# y en el siguiente post, haremos esto mismo pero con Java.

En primer lugar crearemos un clase  Persona, dándole algunas propiedades como nombre, apellidos, nacimiento, un valor booleano para conocer el género, fecha de nacimiento y lugar de nacimiento, además le añadimos una propiedad de solo lectura que calcule la edad, toString, una para obtener el nombre completo y otro método booleano para saber si es nacido en un lugar concreto.

namespace ColeccionesDemo
{
    public class Persona
    {
        public Persona(string _name,
            string _surname,
            bool _isMan,
            DateTime _birthDate,
            string _birthPlace)
        {
            Name = _name;
            SurName = _surname;
            IsMan = _isMan;
            BirthDate = _birthDate;
            BirthPlace = _birthPlace;
        }

        public string Name { get; set; }
        public string SurName { get; set; }
        public DateTime BirthDate { get; set; }
        public string BirthPlace { get; set; }
        public bool IsMan { get; set; }
        public int Age
        {
            get
            {
                DateTime now = DateTime.Now;
                return now.Year - BirthDate.Year + (now.DayOfYear Nombre: {0}, Apellidos: {1}, Edad: {2}, De: {3}", Name, SurName, Age, BirthPlace); }
        }
        public string FullName
        {
            get { return string.Format("{0} {1}", Name, SurName); }
        }
        public override bool Equals(object obj)
        {
            var persona = obj as Persona;
            return persona != null &&
                   Name == persona.Name &&
                   SurName == persona.SurName;
        }
    }
}

Una vez creada la clase persona, para C# vamos a crear un objeto que almacene esta clase con una colección List la cual implementa la interfaz IEnumerable y a la cual le añadiremos algunos individuos ficticios.

      static List personas = new List();

        static void addPersonas()
        {
            personas.Add(new Persona("Joaquin", "Martinez Rus", true, new DateTime(1969, 2, 20), "Linares"));
            personas.Add(new Persona("Vicky", "Diez Calatayud", false, new DateTime(1996, 4, 19), "Calatayud"));
            personas.Add(new Persona("Ana Isabel", "Martinez Baloo", false, new DateTime(1998, 10, 20), "Cordoba"));
            personas.Add(new Persona("Victoria", "Martinez Nurse", false, new DateTime(1992, 1, 21), "Cordoba"));
            personas.Add(new Persona("Ana", "Rus Maria", false, new DateTime(1961, 11, 3), "Linares"));
            personas.Add(new Persona("Manuel", "Bonillo Contador", true, new DateTime(1978, 12, 26), "Cordoba"));
            personas.Add(new Persona("Jose Antonio", "Martinez Arcos", true, new DateTime(1974, 9, 4), "Zaragoza"));
            personas.Add(new Persona("Vicente", "Rodriguez Iglesias", true, new DateTime(1981, 11, 8), "Cordoba"));
            personas.Add(new Persona("Alfonso", "Perez Judicial", true, new DateTime(2000, 5, 5), "Linares"));
            personas.Add(new Persona("Ana", "Martinez Maestre", false, new DateTime(2004, 3, 4), "Linares"));
            personas.Add(new Persona("Magdalena", "Fuentes Cruz", false, new DateTime(2002, 7, 11), "Jaen"));
            personas.Add(new Persona("Jose", "Martinez Cintas", true, new DateTime(1981, 6, 21), "Linares"));
            personas.Add(new Persona("Jose", "Aldea Morata", true, new DateTime(1994, 11, 22), "Calatayud"));
            personas.Add(new Persona("Maria Isabel", "Diez Campieles", false, new DateTime(2005, 8, 1), "Calatayud"));
            personas.Add(new Persona("Maria", "Bella Adriá", false, new DateTime(2001, 10, 22), "Jaen"));
            personas.Add(new Persona("Pedro José", "Garcia Civil", true, new DateTime(1980, 9, 15), "Cordoba"));
            personas.Add(new Persona("Luis", "Jiloca Diez", true, new DateTime(1995, 6, 15), "Zaragoza"));
            personas.Add(new Persona("Juan", "Pintor Escultor", true, new DateTime(2000, 10, 22), "Jaen"));
            personas.Add(new Persona("Juan", "Goran Esteban", true, new DateTime(1974, 7, 14), "Jaen"));
            personas.Add(new Persona("Andrea", "Jiloca Diez", false, new DateTime(1999, 9, 21), "Calatayud"));
            personas.Add(new Persona("Daniel", "Ceular Flower", true, new DateTime(1975, 2, 4), "Cordoba"));<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
        }

Una vez añadidos, vamos a pedirle a nuestra colección de personas unas cuantos datos con criterios concretos.
Ejemplo 1. ¿cual es el promedio de edad de todas las personas nacidas en Calatayud?
Vamos a crear tres métodos, uno paso a paso, calcAverageAge(string _birthPlace), es decir inicializamos variables, iteramos por la colección, comprobamos la condición, calculamos e imprimimos. El segundo método mediante programación funcional calcAverageAgeFunctionalProgramming(string _birthPlace), escribiremos una línea para calcular el promedio y otra para imprimirlo (aunque lo podía haber hecho en la misma línea), por último otro modo sería con Linq igual de vistoso que el anterior con el método calcAverageAgeLinq(string _birthPlace)

static void calcAverageAge(string _birthPlace)
        {
            double suma = 0;
            double count = 0;
            double average = 0;
            foreach (var persona in personas)
            {
                if (persona.IsFrom(_birthPlace))
                {
                    suma += persona.Age;
                    count++;
                }
            }
            average = suma / count;
            Console.WriteLine(string.Format("Las personas nacidas en {0} tienen un promedio de edad de {1} ", _birthPlace, average));

        }

        static void calcAverageAgeFunctionalProgramming(string _birthPlace)
        {
            var average= personas.Where(n => n.IsFrom(_birthPlace)).Average(p => p.Age);
            Console.WriteLine(string.Format("Programación funcional\nLas personas nacidas en {0} tienen un promedio de edad de {1} ", _birthPlace, average));
        }

        static void calcAverageAgeLinq(string _birthPlace)
        {
            var average = (from u in personas
                         where u.IsFrom(_birthPlace)
                         select u).Average(p => p.Age);
            Console.WriteLine(string.Format("Programación funcional\nLas personas nacidas en {0} tienen un promedio de edad de {1} ", _birthPlace, average));
        }

Ejemplo 2. Queremos listar todos los mayores de edad por orden alfabético de los apellidos.
Con el método estándar printAdults() y como queremos ordenar por los apellidos hemos tenido que incluir la interfaz IComparable que implementa el método CompareTo(Persona other) efectuando la comparación de los apellidos y ejecutando el método Sort de la clase List. En el siguiente método con programación funcional printAdultsFunctionalProgramming(), en una sola línea efectuamos todas las operaciones sin hacer referencia a ninguna interfaz IComparable y por último el mismo método basado en Linq printAdultsLinq(). Este tipo de expresiones en una línea, las llamamos expresiones lambda.

static void printAdults()
        {
            personas.Sort();
            foreach (var persona in personas)
            {
                if (persona.Age>17)
                {
                    Console.WriteLine(persona.FullName);
                }
            }
        }

        static void printAdultsFunctionalProgramming()
        {
            Console.WriteLine("******************************************");
            Console.WriteLine("Mayores de edad con programación funcional");
            Console.WriteLine("******************************************");
            personas.Where(p => p.Age > 17).
                OrderBy(p=>p.SurName).
                ToList().
                ForEach(p => Console.WriteLine(p.FullName));
        }

        static void printAdultsLinq()
        {
            Console.WriteLine("************************");
            Console.WriteLine("Mayores de edad con Linq");
            Console.WriteLine("************************");
            (from persona in personas
                      where persona.Age > 17
                      orderby persona.SurName
                      select persona).ToList().ForEach(p => Console.WriteLine(p.FullName));
        }

Resultado, el mismo, pero a mi entender, claridad en el código máxima con programación funcional. En el siguiente post, haremos lo mismo pero con Java.
coleccion1coleccion2

DefaultTableModel extendido

DefaultTableModel extendido

A veces cuando programamos en varios lenguajes, no podemos impedir comparar el modo de hacer entre unos y otros y uno de ellos es el uso de un control JTable y su relleno con DefaultTableModel. Comparado con un DataGrid en WPF al que le pasamos la colección de objetos y si así lo deseamos, las columnas pueden generarse solas, nuestro JTable está un poco lejos ya que hay que crear las columnas y pasarle un array de objetos por fila, pero por ejemplo al seleccionar una fila, como el objeto no está incluido en ella,sino un array, hay que recomponer de nuevo el objeto, en fin, demasiados inconvenientes.

Para solucionar esto, vamos a crear un objeto DefaultTableModel al que le pasaremos como argumentos la lista de objetos, los nombres de las columnas, el valor de la key para localizar objetos y un texto para filtros y con todo esto añadiremos algunas funciones adicionales como filtrar u obtener un objeto.

Para generalizar, he creado una interface ObjectTableable para el objeto en sí, que implementa tres métodos:

  • Object[] toArray(). Obtiene un array del objeto con el fin de añadirlo a cada fila
  • int GetIndex(). Nos informa de la columna que contiene el key del objeto y con el cual podemos luego capturar.
  • Boolean Contains(String text). Comprueba en sus propiedades si contiene un texto
public interface ObjectTableable{
    public Object[] toArray();
    public Object getIndex();
    public Boolean contains(String text);
}

La siguiente interface la implementará nuestra clase extendida DefaultTableModel a la cual le pasamos un objeto genérico que implementa la interface ObjectTableable, con esto nos aseguramos que todos los objetos de nuestra clase extendida funciona por igual. Esta interface se llama Tableable y contiene los siguientes métodos:

  • int getKeyIndex(). Devuelve el número de columna que contiene el key del objeto en la lista
  • void setKeyIndex(int index). Asigna el valor de la columna key
  • T getRowObject(). Devuelve un objeto que implementa la interfaz ObjectTableable
  • ArrayList getColumns(). Obtiene una lista de las columnas
  • void setColumns(String [] columns). Asigna el valor de las columnas
  • void clearColumns(). Borra las columnas. Esto solo se puede hacer desde el objeto jTable.ColumnTableModel.
  • void filter(String text). Filtra el contenido de la colección mediante un texto.
public interface Tableable{
    int getKeyIndex();
    void setKeyIndex(int index);
    ArrayList getColumns();
    void setColumns(String [] columns);
    void clearColumns();
    T getRowObject(int _row);
    void filter(String text);
}

Un ejemplo de un un objeto que implementa la interfaz ObjectTableable sería este:

public class Cliente implements ObjectTableable {
// campos y métodos
//...
@Override
    public Object[] toArray() {
        return new Object[]{
            getCustomerNumber(),
            getCustomerName(),
            getContactFirstName(),
            getContactLastName(),
            getPhone(),
            getAddressLine1(),
            getAddressLine2(),
            getCity(),
            getState(),
            getPostalCode(),
            getCountry(),
            getSalesRepEmployeeNumber(),
            getCreditLimit()
        };
    }

    @Override
    public Object getIndex() {
        return 0;
    }

    @Override
    public Boolean contains(String text) {
        String lowerText=text.toLowerCase();
        return this.getCustomerName().toLowerCase().contains(lowerText) ||
                String.valueOf(getCustomerNumber()).contains(lowerText) ||
                this.getContactFirstName().toLowerCase().contains(lowerText) ||
                this.getContactLastName().toLowerCase().contains(lowerText);
    }
}

El método toArray(), devuelve un array de los objetos que pretendemos visualizar y contains le indicamos si en alguno de sus campos contiene el elemento que buscamos.

Y ahora la extensión de TableDefaultModel, la cual debe tratar objetos genéricos para que nos sirva para cualquier objeto que implemente nuestra initerfaz.

public class ExtendedTableModel<T extends ObjectTableable> extends DefaultTableModel implements Tableable{
     
    ArrayList<T> objectList;
    ArrayList<String> columns;
    int keyIndex=0;
    
    public ExtendedTableModel(ArrayList<T> _list, String[] _columns){ 
        this(_list,_columns,0, "");  
    }
    
    public ExtendedTableModel(ArrayList<T> _list, String[] _columns, int _key){ 
        this(_list,_columns,_key,"");         
    }
    
        public ExtendedTableModel(ArrayList<T> _list, String[] _columns, int _key, String text){ 
        objectList=new ArrayList<>();
        columns=new ArrayList<>();
        keyIndex=_key;
                
        objectList.addAll(_list);
        setColumns(_columns);
        if (!text.isEmpty()) {
            filter(text);
        }
        setModel();           
    }
        
    void setModel(){ 
        setColumns();
        objectList.stream().forEach((object) -> {
            this.addRow(object.toArray());
        });
    }
    
    void setColumns(){
        getColumns().stream().forEach((column) -> {
            this.addColumn(column);
        });
    }
    
    @Override
    public T getRowObject(int row){     
        Object keyRow=getValueAt(row, keyIndex);
        for (T object : objectList) {
            Object a= object.getIndex();
            if (object.getIndex().equals(keyRow)) {
                return object;
            }
        }
        return null;
    }

    @Override
    public int getKeyIndex() {
        return keyIndex;
    }

    @Override
    public void setKeyIndex(int index) {
        keyIndex=index;
    }

    @Override
    public ArrayList<String> getColumns() {
        return columns;
    }

    @Override
    public void setColumns(String[] _columns) {
        columns.addAll(Arrays.asList(_columns));
    }

    @Override
    public void clearColumns() {
        setColumns(new String[0]);
    }    
    
    @Override
    public void filter(String text){
        Object[] temp=objectList.stream().filter(k->k.contains(text)).toArray();
        objectList.clear();
        for (Object object : temp) {
            objectList.add((T)object);
        } 
    }       

al instanciar el objeto, ya se crea el modelo con las columnas y filas idenpendientemente del tipo de objeto siempre implemente nuestra interfaz, pero si hacemos dobleclick sobre el jTable, podemos llamar al método getRowObject que devolverá el objeto completo o si le passamos como parámetro un texto, iniciará un filtrado sobre los objetos mostrando solo los que cumplan el criterio.Con esto, simulamos un itemsource a un control jTable de Java, primero obtenemos los datos, segundo las columnas, el texto de filtrado y la columna del indice.

ArrayList empleados=negocio.getEmpleados();
String [] _columnsE=new String[] { "Cargo", "Código empleado", "Nombre", "Apellidos","Extensión", "Email", "Oficina"};
                etm=new ExtendedTableModel(empleados,_columnsE,1, jTextField1.getText());

Y el resultado.

Video13.gif

Validar email con PHP

Validar email con PHP
A continuación dos modos de validar una dirección de email con php.
La primera mediante una expresión regular y la segunda mediante filter_var que se encarga de filtrar variables mediante filtros (valga la redundancia).
Como ejemplo, un pequeño formulario con un inputtype tipo texto y un botón de envío.

<HTML>
<HEAD></HEAD>

    <BODY>
        <p>Validando email</p>
        <form action="" method="post">
            <input type="text" value="" name="email"/>
            <input type="submit" value="validar" />
        </form>
    </BODY>
    <?php
    $email=isset($_POST['email']) ? $_POST['email'] :null;    
    if(validarEmail_ExpresionRegular($email)){          
            echo "Expresion Regular. La dirección de email $email es correcta.</br>";
    }
    else echo "Expresion Regular. La dirección de email $email es incorrecta.</br>";    
    
    if (is_valid_email_FilterVar($email)){
          
            print "Filter_var. La dirección de email $email es correcta.</br>";  
    }
    else print "Filter_var. La dirección de email $email es incorrecta.</br>"; 
    
    /* **********************************
    *  FUNCIONES DE VALIDACIÓN DE EMAIL *
    *************************************/
    
    // Función para validar email usando un expresión regular
    function validarEmail_ExpresionRegular($emailAValidar){
        $matches = null;
            return (1 === preg_match('/^[A-z0-9\\._-]+@[A-z0-9][A-z0-9-]*(\\.[A-z0-9_-]+)*\\.([A-z]{2,6})$/', $emailAValidar, $matches));
    }
    
    // Función para validar email usando un filter_var 
    // en la que se filtran variables mediante filtros (valga la redundancia)
    function is_valid_email_FilterVar($str)
    {
        return (false !== filter_var($str, FILTER_VALIDATE_EMAIL));
    }
?>
</HTML>

Descomposición factorial con hilos II

Descomposición factorial con hilos II
Y ahora vamos a emular un lugar donde se descomponen los números y cada vez que se encuentra uno, se obtiene y se muestra su descomposición.

Para realizar esto, usaremos los monitores de Java, los métodos wait() y notify(). Estos métodos tienen que ir siempre incluidos sobre métodos marcados como syncronized o usar el método syncronized(metodo sincronizado). wait() y notify() (hay alguno más) heredan del Object, por lo que todos los objetos que hereden de esta clase, lo tienen disponible.

¿Que hace wait()? suspende indefinidamente el hilo hasta que se reanude con notify().

Así que crearé una clase que solicitará la descomposición del número, el cual es enviado al supuesto servidor compartido de descomposiciones factoriales, este se encarga de descomponerlo (tarea dura) y una vez que termine, habrá un receptor de datos esperando a su finalización para mostrar su descomposición.

DESC

La clase SolicitudDescomposicionVisualizadorDescomposicion heredan de Thread, los iniciamos desde la clase principal y a trabajar por parte del servidor. He aquí el código:

public static void main(String[] args) {
        // TODO code application logic here
        
        ServidorDescomposicion r=new ServidorDescomposicion();
        for (int i = 0; i < 10; i++) {
            SolicitudDescomposicion productor=new SolicitudDescomposicion(i, r);
            VisualizadorDescomposicion consumidor=new VisualizadorDescomposicion(i, r);
            
            productor.start();
            consumidor.start();
        }
        
    }
public class SolicitudDescomposicion extends Thread {
    
    ServidorDescomposicion r;
    
    public SolicitudDescomposicion(int n, ServidorDescomposicion _r){
        this.setName("Productor " + n);
        r=_r;
    }
    
    @Override
    public void run(){
        int n=Math.abs(new Random().nextInt());
        System.out.println("Enviando número descomposición desde el productor:\t" + n);
        r.descomponerNumero(n);
    }
}

public class VisualizadorDescomposicion extends Thread{
    
    ServidorDescomposicion r;
    
    public VisualizadorDescomposicion(int n, ServidorDescomposicion _r){
        this.setName("Consumidor " + n);
        r=_r;
    }
    
    @Override
    public void run(){        
        String desc="";
        try {
            desc = r.getDescomposicion();
        } catch (InterruptedException ex) {
            Logger.getLogger(VisualizadorDescomposicion.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Datos obtenidos desde el consumidor.Resultado:\t\t" + desc);        
    }
}
public class ServidorDescomposicion {

    ArrayList buffer;
    boolean existData;


    //&& estado.equals(estadoEnum.DESCOMPONIENDO
    //&& estado.equals(estadoEnum.LIBRE)
    public ServidorDescomposicion() {
        buffer = new ArrayList();
    }

    public synchronized void descomponerNumero(int numero) {
        descomponer(numero);
    }

    void retardo(int ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException ex) {
            Logger.getLogger(ServidorDescomposicion.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public synchronized String getDescomposicion() throws InterruptedException {
        
        while(!existData){
            try {
                wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(ServidorDescomposicion.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        
        String descomposicion = "";
        descomposicion = buffer.remove(0);
        if (buffer.size()==0) {
            existData=false;
        }
        notify();
        
        return descomposicion;
    }

    void descomponer(int numero) {
        // Cálculos y resultados
        int iniNum = numero;
        int numeroAux = numero;
        int n = 0;
        int nn = 0;

        String text = "";
        String puntos = ".";

        for (long i = 2; i < numero; i++) { 
            while (numeroAux % i == 0) {
                numeroAux /= i;
                text += i + ".";
                if (numeroAux == 1) {
                    numero = numeroAux;
                }
            }
        }
        if (text.isEmpty()) {
            System.out.printf("El número %s es primo!\n", iniNum);
            text = String.valueOf(iniNum);
        }
        buffer.add(String.format("%s=%s", iniNum, text));
        existData=true;

    }

}

y el resultado para 10 números enteros


Enviando número descomposición desde el productor:	1007666687
Enviando número descomposición desde el productor:	233955388
Enviando número descomposición desde el productor:	403028651
Enviando número descomposición desde el productor:	1405658987
Enviando número descomposición desde el productor:	809322159
Enviando número descomposición desde el productor:	263332588
Enviando número descomposición desde el productor:	1552584352
Enviando número descomposición desde el productor:	1342709543
Datos obtenidos desde el consumidor.Resultado:		1007666687=17.31.43.53.839.
Datos obtenidos desde el consumidor.Resultado:		1342709543=7.191815649.
Datos obtenidos desde el consumidor.Resultado:		1552584352=2.2.2.2.2.11.89.49559.
Datos obtenidos desde el consumidor.Resultado:		263332588=2.2.487.135181.
Datos obtenidos desde el consumidor.Resultado:		809322159=3.113.733.3257.
Datos obtenidos desde el consumidor.Resultado:		403028651=67.6015353.
Datos obtenidos desde el consumidor.Resultado:		233955388=2.2.31.443.4259.
Datos obtenidos desde el consumidor.Resultado:		1405658987=127.199.55619.

Saludos

Descomposición factorial con hilos I

Descomposición factorial con hilos I

Un ejemplo de aprovechamiento de recursos sobre procesos penosos en los que ponemos el pc a prueba, puede ser la descomposición de números grandes en factores primos. En este ejemplo sobre la plataforma Java, se descomponen números del tipo Long con un método estándar (no muy eficiente) con una clase que implementa la Interfaz Runnable. A la clase le pasamos un número como parámetro y otro de identificador.Si creamos varios hilos, cada uno descomponiendo un número grande, aprovechará los distintos núcleos para el cálculo. Este es el resultado para números enteros pequeños mostrando el número de hilos vivos.

INICIO Hilo nº0-> Descomposición de 1763458
INICIO Hilo nº2-> Descomposición de 882375341
INICIO Hilo nº3-> Descomposición de 396209470
INICIO Hilo nº1-> Descomposición de 1633289887
Hilo nº 0-> Descomponiendo 1763458. Nº iteraciones: 1
Hilo nº 2-> Descomponiendo 882375341. Nº iteraciones: 96
Hilo nº 3-> Descomponiendo 396209470. Nº iteraciones: 1
Hilo nº 3-> Descomponiendo 198104735. Nº iteraciones: 4
Hilo nº 3-> Descomponiendo 39620947. Nº iteraciones: 18
Hilo nº 3-> Descomponiendo 2085313. Nº iteraciones: 210
Hilo nº 1-> Descomponiendo 1633289887. Nº iteraciones: 66
Hilo nº 1-> Descomponiendo 24377461. Nº iteraciones: 100
Hilo nº 3-> Descomponiendo 9883. Nº iteraciones: 9882
FIN Hilo nº 3-> 396209470 = 2*5*19*211*9883*. Nº iteraciones: 9882
Quedan 3 hilos vivos
Hilo nº 2-> Descomponiendo 9096653. Nº iteraciones: 1810
Hilo nº 2-> Descomponiendo 5023. Nº iteraciones: 5022
FIN Hilo nº 2-> 882375341 = 97*1811*5023*. Nº iteraciones: 5022
Quedan 2 hilos vivos
Hilo nº 1-> Descomponiendo 241361. Nº iteraciones: 241360
FIN Hilo nº 1-> 1633289887 = 67*101*241361*. Nº iteraciones: 241360
Quedan 1 hilos vivos
Hilo nº 0-> Descomponiendo 881729. Nº iteraciones: 881728
FIN Hilo nº 0-> 1763458 = 2*881729*. Nº iteraciones: 881728
Quedan 0 hilos vivos

Y el código de las clases…

Clase Main

package Descompositor;

import java.util.Random;

// <editor-fold defaultstate="collapsed" desc="Cabecera de clase">
/******************************************************
 *  @author:    Joaquín Martínez Rus (c) 2017
 *  @version:   1.0
 *  File:       Main.java
 *  Created:    29/11/2017
 *  Project:    PSP. Ejemplo de descomposición multihilo.
 *  Comments:
 *******************************************************/
// </editor-fold>
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        for (int i = 0; i < 5; i++) {
            Descomposicion d=new Descomposicion(Math.abs(new Random().nextLong()),i);
            Thread hilo=new Thread(d);
            hilo.start();
        }
    }
}

y la clase encargada de la descomposición

package Descompositor;
import java.util.Date;
// <editor-fold defaultstate="collapsed" desc="Cabecera de clase">
/******************************************************
 *  @author:    Joaquín Martínez Rus (c) 2017
 *  @version:   1.0
 *  File:       Descomposicion.java
 *  Created:    29/11/2017
 *  Project:    PSP. Ejemplo de descomposición multihilo.
 *  Comments:
 *******************************************************/
// </editor-fold>
public class Descomposicion implements Runnable{

    public Descomposicion(long n, int j){
        this.name=j;
        this.number=n;
        Descomposicion.instanciasVivas++;
    }

    public static int instanciasVivas;
    int name;
    long number;

    @Override
    public void run() {
        descomponer(number, name);
    }

    void descomponer(long numero, int j){
        // Cálculos y resultados

        long iniNum=numero;
        long numeroAux = numero;
        long n=0;
        int nn=0;

        System.out.printf("INICIO Hilo nº%s-> Descomposición de %s\n" , j, numeroAux);
        String text="";
        String puntos=".";

        for (long i = 2; i 1000000000) {
                nn++;
                String cadena="Hilo Nº %s-> Seguimos calculando para %s...\n";
                if (nn>2) {
                    if (text.isEmpty()) {
                        cadena = "Hilo Nº %s-> parece que el número %s es primo...\n";
                    }
                    else{
                        cadena ="Hilo Nº %s-> No es primo y seguimos calculando para %s...\n";
                        nn=0;
                    }
                }
                System.out.printf(cadena, j, numeroAux);
                n=0;

            }
            // DESCOMPOSICIÓN
            while (numeroAux % i == 0) {
                System.out.printf("Hilo nº %s-> Descomponiendo %s. Nº iteraciones: %s\n",j, numeroAux, n);
                numeroAux /= i;
                text += i + "*";
                if (numeroAux == 1) {
                    numero=numeroAux;
                }
            }
        }
        if (text.isEmpty()){
            System.out.printf("El número %s es primo!\n",iniNum);
            text = String.valueOf(iniNum);
        }
        System.out.printf("FIN Hilo nº %s-> %s = %s. Nº iteraciones: %s\n",j, iniNum, text, n);

        Descomposicion.instanciasVivas--;
        System.out.printf("Quedan %s hilos vivos\n",Descomposicion.instanciasVivas);

    }
}

Os adjunto el proyecto de NetBeans.

Saludos

 

Atajos en Android Studio

Atajos en Android Studio

Como no iba a ser menos, Android Studio también tiene algunos atajos o métodos abreviados para simplificar la escritura de código y he aquí algunos ejemplos útiles.

¿Cuáles son estas abreviaturas? Pues si pulsamos CTRL + J nos muestra en una lista todos ellas.
Pulsando por ejemplo it y CTRL + J, mostraría lo siguiente
abrev01
y escribiendo st + TAB escribe String
Si declaramos por ejemplo un array y luego itar + TAB se genera el siguiente código

String [] array=new String[3];
for (int i = 0; i < array.length; i++) {
       String s = array[i];                    
}

Hay muchas abreviaturas, pero por otra parte, existen combinaciones de teclas y a mi personalmente, me gustan las siguientes:

Cuando vamos a hacer un cast, escribimos el paréntesis y CTRL + MAYUSC + SPC y se completa automáticamente

String a=( CTRL + MAYUSC + SPC → String a=(String)
CTRL + SPC nos muestra las sugerencias en el contexto actual. Si escribimos nu…abrev02

CTRL + P entre los paréntesis donde se albergan los parámetros de un método, nos muestra una ayuda de los parámetros

abrev03

CTRL + / o CTRL + MAYUSC + / comenta mediante // o /**/ respectivamente las líneas

ALT + CTRL + L formatea el código

CTRL + click sobre un objeto o método, navega hasta la declaración de este

CTRL + MAYUSC + RETROCESO, navega hasta el último lugar donde realizamos la última edición.

…  y muchos más.