Lambdas and functional programming - Java 11
Tags: programming, tutorial, java, codenewbie
Published: 2022-05-05 22:27:29

# Lambdas and Functional Interfaces

## Writing Simple Lambdas

* Functional programming is a way of writing code **more declaratively**. You specify what you want to do rather than dealing with the state of objects. You **focus more on expressions** than loops.
* Functional programming uses lambda expressions to write code. 
*  **Lambda expression** is an unnamed method.

## LAMBDA EXAMPLE

```java
public class Animal {

   private String especie;
   private boolean podeSaltar;
   private boolean podeNadar;

   public Animal(String nomeDaEspecie, boolean saltador, boolean nadador){
      especie = nomeDaEspecie;
      podeSaltar = saltador;
      podeNadar = nadador;
   }

   public boolean podeSaltar() { return podeSaltar; }
   public boolean podeNadar() { return podeNadar; }
   public String toString() { return especie; }
}
```

```java
public interface AnalisadorDeAnimal {
   boolean teste(Animal a);
}
```

```java
import java.util.ArrayList;
import java.util.List;

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

        // lista de animais
        List<Animal> animais = new ArrayList<Animal>();
        animais.add(new Animal("peixe", false, true));
        animais.add(new Animal("canguru", true, false));
        animais.add(new Animal("coelho", true, false));
        animais.add(new Animal("tartaruga", false, true));

        // imprime os animais verificados
        imprimir(animais, new VerificaSeSaltador());
    }
    private static void imprimir(List<Animal> animais, Verificador verificador) {
        for (Animal animal : animais) {
            // verificando
            if (verificador.verificar(animal)) {
                System.out.print(animal + " ");
            }
        }
        System.out.println();
    }
}
```
```
canguru coelho
```
* what if we want to verify if the animal can swin?
* alternative: **lambdas**
```java
// imprime os animais que podem saltar  
imprimir(animais, animal -> animal.podeSaltar());
```
or
```java
// imprime os animais que podem nadar  
imprimir(animais, animal -> animal.podeNadar());
```

## Lambda Syntax

* Lambdas work with interfaces that have only one abstract method.

```java
	animal -> animal.podeSaltar()
``` 
* syntax:
	* a single parameter (animal)
	* the arrow to separate the parameter and body;
	* a body that calls a single method and returns the result of that method

```java
(Animal animal) -> {return a.podeSaltar();}
``` 

* syntax
	* A single parameter specified with the name animal and stating the type is Animal
	* The arrow operator to separate the parameter and body
	* A body that has one or more lines of code, including a semicolon and a return statement
* The parentheses can be omitted only if there is a single parameter;
* Type is not explicitly stated;
* we can omit braces when we have only a single statement.
	*  Java doesn’t require you to type return or use a semicolon when no braces are used. 

## Introducing Functional Interfaces

* *functional interfaces* are interfaces that have only one abstract method;
* you should know the following built-in functional interfaces:  _Predicate_, _Consumer_, _Supplier_, and _Comparator_;

### PREDICATE

```java
public interface Predicate<T> {
   boolean test(T t);
}
```

```java
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class UsoDoPredicate {

    public static void main(String[] args) {
        List<Animal> animais = new ArrayList<>();
        animais.add(new Animal("peixe", false, true));
        animais.add(new Animal("canguru", true, false));
        
        print(animais, a -> a.podeSaltar());
    }
    private static void print(List<Animal> animais, Predicate<Animal> verificador) {
        for (Animal animal : animais) {
            if (verificador.test(animal))
                System.out.print(animal + " ");
        }
        System.out.println();
    }
}
```

```
canguru
```

### CONSUMER

```java
public interface Consumer<T> {
    void accept(T t)
}
```

```java
import java.util.function.Consumer;

public class UsoDoConsumer {

    public static void main(String[] args) {
        Consumer<String> consumer = x -> System.out.println(x);
        print(consumer, "Hello World");
    }
    private static void print(Consumer<String> consumer, String value) {
        consumer.accept(value);
    }
}
```

``` 
Hello World
```

### SUPPLIER

```java
public interface Supplier<T> {  
     T get();  
}
```

```java
import java.util.function.Supplier;

public class UsoDoSupplier {

    public static void main(String[] args) {
        Supplier<Integer> number = () ->  42;
        System.out.println(returnNumber(number));
    }

    private static int returnNumber(Supplier<Integer> supplier) {
        return supplier.get();
    }
}
```

```
42
```

## COMPARATOR

* rules, if returns:
	* a negative number means the first value is smaller;
	* zero means they are equal, 
	* and a positive number means the first value is bigger.

```java
import java.util.Arrays;
import java.util.Comparator;

public class UsoDoComparator {

    public static void main(String[] args) {
        Integer [] array = {4, 1, 7, 2, 5};
        print(array, (i1, i2) -> i1 - i2);
    }

    public static void print(Integer [] array, Comparator<Integer> comparator) {
        Arrays.sort(array, comparator);
        System.out.println(Arrays.toString(array));
    }
}
```
```
[1, 2, 4, 5, 7]
```

## Working with Variables in Lambdas
* places can appear:
	* parameter list;
	* local variables declared inside the lambda body;
	* variables referenced from the lambda body;
* Method parameters and local variables are allowed to be referenced if they are effectively final (the value of a variable doesn’t change after it is set).

##  Calling APIs with Lambdas

```java
import java.util.ArrayList;
import java.util.List;

public class ExemploUsandoLambdasEmAPI {

    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Joao");
        names.add("Jose");
        names.add("Maria");
        System.out.println("Nomes: " + names);

        names.removeIf(name -> !name.startsWith("J"));
        System.out.println("Nomes iniciando com J: " + names);

        names.add("Araci");
        names.add("Ze");
        System.out.println("\nNomes: " + names);

        names.sort((name1, name2) -> name1.compareTo(name2));
        System.out.println("Nomes ordenados: " + names);

        System.out.println("\nImprimindo novamente");
        names.forEach(name -> System.out.println(name));

    }
}
```

```
Nomes: [Joao, Jose, Maria]
Nomes iniciando com J: [Joao, Jose]

Nomes: [Joao, Jose, Araci, Ze]
Nomes ordenados: [Araci, Joao, Jose, Ze]

Imprimindo novamente
Araci
Joao
Jose
Ze
```

### REMOVEIF()
* takes a Predicate to decide what to remove from the list.

### SORT()
*  The sort() method takes Comparator that provides the sort order.

### FOREACH()
* It takes a *Consumer* and calls that lambda for each element encountered.