Java 8: Espressioni Lambda in 5 minuti

– Indice Tutorial –

Java Lambda: cosa sono

java lambda

Le Java Lambda costituiscono la principale novità per il linguaggio di programmazione Java 8. Esse sono collegate al concetto di funzione anonima (funzione non classe anonima), ossia una funzione che ha un corpo ma non un nome, definita nel punto in cui viene utilizzata. La loro sintassi è qualcosa di simile:

(arg1, arg2) -> {body}

Java 8 Lambda: Esempi
// espressione che prende in input due interi e restituisce la somma
(int x, int y) -> x + y

// espressione che prende in input una stringa e restituisce la sua lunghezza
s -> s.length()

// espressione senza argomenti che restituisce il valore 50
() -> 50

// espressione che prende in input una stringa e non restituisce nulla
(String s) -> { System.out.println(“Benvenuto “);
System.out.println(s); }

//ERRORE
(int x, 5) -> x + y
In un’espressione lambda o nessuno dei tipi dei parametri è dichiarato oppure lo devono essere tutti. Se c’è solamente un parametro, le parentesi tonde possono essere omesse,
Vengono chiamate interfacce funzionali (functional interface) delle interfacce con un solo metodo astratto. Sono generalmente marcate con l’annotazione @FunctionalInterface, anche se non è obbligatorio. Le lambda sono usate con le funcional interface.

Esempio:
// Anonymous Runnable
Runnable r1 = new Runnable(){

@Override
public void run(){
System.out.println(“Hello world old style!”);
}
};

// Lambda Runnable
Runnable r2 = () -> System.out.println(“Hello world with Lambda!”);

E’ abbastanza evidente come con l’uso delle lambda abbiamo ridotto un pezzo di codice da 5 linee a 1 soltanto.
Esempio:

//Prima:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(“Sintassi arcinota!”);
}
});

//Dopo:
button.addActionListener( (e) -> {
System.out.println(“Nuova sintassi!”);
});

Ricapitolando, l’espressione lambda è una sintassi più semplice e leggibile per definire-creare un’istanza di una classe anonima che implementa un’interfaccia con un solo metodo astratto. Esse si concentrano solamente sulla definizione dell’unico metodo astratto dell’interfaccia.

Usando le espressioni lambda si può utilizzare un altro strumento aggiunto con java8, i reference method. E’ una nuova sintassi per poter invocare un metodo o un costruttore già esistente.
Esempio:
class Numbers {
public static boolean isMoreThanFifty(int n1, int n2) {
return (n1 + n2) > 50;
}

}

public static void main(String[] args) {

// Using an anonymous class
BiPredicate<Integer, Integer> a = new BiPredicate<Integer, Integer>() {
public boolean test(Integer i1, Integer i2) {
return Numbers.isMoreThanFifty(i1, i2);
}
};

// Using a lambda expression
BiPredicate<Integer, Integer> b = Numbers::isMoreThanFifty;

// Using a method reference
BiPredicate<Integer, Integer> c = (i1, i2) -> Numbers.isMoreThanFifty(i1, i2);

//i tre oggetti sono equivalenti
System.out.println(a.test(2, 3));
System.out.println(b.test(2, 3));
System.out.println(c.test(2, 3));

}
da notare che il metodo isMoreThanFifty ha bisogno di due parametri in input. Con il method reference non sono stati menzionati. Questo perche quando invochiamo il metodo test sull’istanza a.test(10,15), i parametri in input vengono passati in automatico al metodo Numbers.isMoreThanFifty(10, 15).

In generale la sintassi di un method reference può essere una delle seguenti:

NomeClasse::metodoIstanza // Il primo parametro è l’oggetto su cui è invocato
// il metodo e gli eventuali altri parametri sono
// passati al metodo
NomeClasse::metodoStatico // Tutti i parametri sono passati al metodo
oggetto::metodoIstanza // Tutti i parametri sono passati al metodo
E’ possibile anche invocare il costruttore con la stessa sintassi:
String:new

Esempio:

BiPredicate<String,String> eqstr = (s1,s2) -> s1.equals(s2);

con lambda diventa

BiPredicate<String,String> eqstr = String::equals;

eqstr.test(tmp, tmp2);

ossia il metodo equals sarà chiamato su tmp:

tmp.equals(tmp2);

Se ti può interessare, di seguito trovi la versione video di questo articolo:

Check esistenza file

        String pathFile = “/photos/profile/photoProfile.png”;
        File file = new File(pathFile);

         boolean existsFile = file.isFile();
        if (!existsFile) {
          System.out.println(“foto profilo non esistente”);
        }
        else
          System.out.println(“foto profilo  esistente”);

Java StringTokenizer Example

La classe StringTokenizer è usata per dividere una stringa in varie sottostringhe, delimitate da un carattere speciale.

1° Esempio – Lettura Stringa

Divisione di una stringa con il carattere speciale blank e la virgola.

StringTokenizer.java
package com;

import java.util.StringTokenizer;

public class StringTokenizerTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  String str = "prova1 prova2 , test1 test2, prova3 test3";
  StringTokenizer st = new StringTokenizer(str);
 
  System.out.println("---- Split by space ------");
  while (st.hasMoreElements()) {
   System.out.println(st.nextElement());
  }
 
  System.out.println("---- Split by comma ',' ------");
  StringTokenizer st2 = new StringTokenizer(str, ",");
 
  while (st2.hasMoreElements()) {
   System.out.println(st2.nextElement());
  }

 }

}


output:
2 Esempio: Lettura File CVS
Le stringhe da splittare sono lette da un file cvs.
friends.cvs
prova| prova1 | prova2| prova3
test | test1  | test2 | test3
CaricaFile.java
package com;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

public class CaricaFile {

 public static void caricaUsers() throws IOException {
  BufferedReader reader = new BufferedReader(new FileReader(
    "D:\friends.txt"));
  String line = reader.readLine();
  while (line != null) {

  StringTokenizer stRecord = new StringTokenizer(line, "|");
   while (stRecord.hasMoreTokens()) {
    String record = stRecord.nextToken();
    System.out.print(record + "  ");
   }
   System.out.println("");
   line = reader.readLine();
  }
 }

 public static void main(String[] args) throws FileNotFoundException,
   IOException {
  caricaUsers();
 }
}


Output:

Java Reflection Esempio

Copiare due classi diverse ma con gli stessi campi tramite la reflection

Bean 

A.java

package com;

import java.lang.reflect.Field;

public class A {
private String name;

private long punteggio;

public long getPunteggio() {
return punteggio;
}

public void setPunteggio(long punteggio) {
this.punteggio = punteggio;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

B.java

package com;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class B {
private String name;

private long punteggio;

public long getPunteggio() {
return punteggio;
}

public void setPunteggio(long punteggio) {
this.punteggio = punteggio;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public void copy(Object obj) {
try {

Method[] methods = obj.getClass().getMethods();

for (int i = 0; i < methods.length; i++) {
String methodName = methods[i].getName();
try{
if(methodName.startsWith(“get”)){
this.getClass().getMethod(methodName.replaceFirst(“get”, “set”) , methods[i].getReturnType() ).invoke(this, methods[i].invoke(obj, null));
}else if(methodName.startsWith(“is”) ){
this.getClass().getMethod(methodName.replaceFirst(“is”, “set”) ,  methods[i].getReturnType()  ).invoke(this, methods[i].invoke(obj, null));
}

}catch (NoSuchMethodException e) {
// TODO: handle exception
}catch (IllegalArgumentException e) {
// TODO: handle exception
}

}

} catch (Exception ex) {
ex.printStackTrace();
}
}

}


Classe per il test:
TestReflection.java
package com;
public class TestReflection {
public static void main(String[] args) {
A obj1 = new A();
obj1.setName(“hello world”);
A obj2 = new A();
obj2.copy(obj1);
System.out.println(“name obj copy with reflection:”+obj2.getName());
}
}
Esecuzione
lanciando il main si ottiene una copia identica dell’istanza obj1:

Read Write File With InputStream OutputStream Java

Le istruzioni che leggono  il  file con InputStream sono:

InputStream inputStream = new FileInputStream(“c:/myFile.txt”);
inputStream.read(bytes);

Per scrivere su un file con OutputStream:

OutputStream outputStream = new FileOutputStream(new File(“c:/myFileNew.txt”));
outputStream.write(bytes, off, len);// scrive un array di byte di  lunghezza len a partire da posizione off

Esempio completo:

package com;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class InputStreamToFile {
    public static void main(String[] args) {

InputStream inputStream = null;
OutputStream outputStream = null;

try {
inputStream = new FileInputStream(“c:/myFile.txt”);

// write the inputStream to a FileOutputStream
outputStream = new FileOutputStream(new File(“c:/myFileNew.txt”));

int read = 0;
byte[] bytes = new byte[1024];

while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}

System.out.println(“Done!”);

} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
// outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}
    }
}

How To Create New File

import java.io.*;

public class CreateFile{
  public static void main(String[] args) throws IOException{
  File f;
  f=new File(“myfile.txt”);
  if(!f.exists()){
  f.createNewFile();
  System.out.println(“New file “myfile.txt” has been created
  to the current directory”);
  }
  }
}

How To Write To File In Java with BufferedWriter

BufferedWriter è una classe per gestire uno  Stream dati di tipo carattere.

package com;
 
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
 
public class WriteToFileExample {
 public static void main(String[] args) {
  try {
 
   String content = "bla bla bla";
 
   File file = new File("/prova/filename.txt");
 
   // if file doesnt exists, then create it
   if (!file.exists()) {
    file.createNewFile();
   }
 
   FileWriter fw = new FileWriter(file.getAbsoluteFile());
   BufferedWriter bw = new BufferedWriter(fw);
   bw.write(content);
   bw.close();
 
   System.out.println("Done");
 
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

HashCode

Quando si ha che fare con gli oggetti, è buona norma riderifinire il metodo equals e anche il metodo hashcode().
In particolare, se abbiamo a che fare per esempio con mappe (hashset, set, etc), gli oggetti verranno inseriti in locazioni di 
memoria identificati con un valore detto bucket. All’interno dello bucket ci possono essere più oggetti.
Questo bucket è dato appunto dal metodo hashCode.
Il metodo hashcode deve essere ridefinito in base alle seguenti regole:
– se due oggetti risultano uguali in base a equals() allora anche i loro hash code devono essere uguali.
– se due oggetti hanno hash code differenti, allora equals() deve indicare che sono diversi.
Esistono anche gli altri 2 casi:
– se due oggetti sono diversi, secondo equals, possono avere hash code uguali o differenti.
– se due oggetti hanno hash code uguali, possono essere uguali o no.
Quando si fa una ricerca di un oggetto nella mappa, prima si controlla se si ha il suo hashcode(bucket),
se, e solo se, il bucket è presente si chiamare il metodo equals per fare l’ultima verifica. Questo 
perche come abbiamo detto nello stesso bucket possono essere inseriti più bucket.