Conhecendo e aplicando um outro paradigma sem sair de sua linguagem favorita!

JAVA é claro! \o/

Rafael Nunes Vieira

7 anos de experiência com Desenv.

Pós Arquitetura de Sistemas Distribuídos

Consultor Desenvolvedor na Sensedia

Me interesso muito por:

#java #javascript #clojure #cleancode #apis #containers #functionalprogramming #architetura

Paradigma funcional no Java

"This is a new way in Java, one that will make our code more expressive, easier to write, less error prone, and easier to parallelize than has been the case with Java until now"

Venkat Subramanian, Functional Programming in Java

Functions as First Class Citizens 

public class MyRunnable implements Runnable {
    public void run(){
        System.out.println("MyRunnable running");
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();

Implements Runnable

Runnable runnable = new Runnable(){
    public void run(){
        System.out.println("MyRunnable running");
    }
};

Thread thread = new Thread(runnable);
thread.start();

Anonymous Implementation of Runnable

Runnable runnable = new Runnable(){
    public void run(){
        System.out.println("MyRunnable running");
    }
};
public class MyRunnable implements Runnable {
    public void run(){
        System.out.println("MyRunnable running");
    }
}
Runnable myRunnable = () -> System.out.println("MyRunnable running");

Thread thread = new Thread(myRunnable);
thread.start();

Lambda implementation

@FunctionalInterface

interface Function<T, R>
interface Supplier<T>
interface Consumer<T>
interface Predicate<T>
...
@FunctionalInterface
interface Callback {
    void call(String response);
}
public static void search(String term, Callback callback) {
    // make async call when it returns run callback
    // function with response
    // {...}
    //

    callback.call(term + " found");
}

@FunctionalInterface

High Order Functions

users.stream().filter((User user) -> user.gender == Gender.MALE)
              .map((User user) -> user.cardLimit)
              .reduce((v1, v2) -> v1 + v2)
              .get()

@FunctionalInterface

Pure Functions

public static int sum(int a, int b) {
    return a + b;
}

Pure function

public static int subtract(int a, int b) {
    return new Random().nextInt() - a - b;
}

public static int multiply(int a, int b) {
    int result = a * b;

    OtherClass.persist(result);

    return result;
} // With side effects

Impure function

"FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY"

Robert C. Martin Clean Code

@Override
public UserCardResponse getCardById(UUID userId, UUID cardId, String expand) {
  // verifica se o usuario existe e nao esta com o status igual a DELETADO.
  UserDomain userDomain = userService.getById(userId);
  if (userDomain == null) {
    throw new NotFoundException(this.messageError.create(Messages.USER_NOT_FOUND));
  }
  // verifica se o card existe
  Integer positionCard = this.positionCard(userDomain.getCard(), cardId);
  if (positionCard < 0) {
    throw new NotFoundException(this.messageError.create(Messages.CARD_NOT_FOUND));
  }
  CardDomain cardDomain = userDomain.getCard().get(positionCard);
  if (ObjectUtils.isEmpty(cardDomain)) {
    throw new NotFoundException(this.messageError.create(Messages.CARD_NOT_FOUND));
  }
  ...
  if (!ObjectUtils.isEmpty(cardDomain.getNumberBin())) {
    Optional<BinDomain> binDomain = this.binRepository.findById(cardDomain.getNumberBin());
    binDomain.ifPresent(cardDomain::setBin);
  }

  UserCardResponse userCardResponse = this.userCardConverter.toCard(cardDomain, expand);
  try {
    CardExpiry cardExpiry = this.getDecryptedExpiry(cardDomain.getDateExpiry());
    userCardResponse.setExpiry(cardExpiry);
  } catch (NullPointerException | NoSuchPaddingException | NoSuchAlgorithmException |
    InvalidKeyException | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException e) {
    log.warn("UserCardController.getCard: " + e.getMessage(), e);
    throw new UnprocessableEntityException(this.messageError.create(Messages.DECIPHER_ERROR),
      "Decipher error", e);
  }
  return userCardResponse;
}

Refactoring

@Override
public UserCardResponse getCardById(UUID userId, UUID cardId, String expand) {
  UserDomain user = getActiveUser(userId);
  Integer positionCard = validateCardExists(cardId, user);
  CardDomain card = getCardFromUser(user, positionCard);
  defineCardBinData(card);
  UserCardResponse userCardResponse = this.userCardConverter.toCard(card, expand);
  defineCardExpiry(card, userCardResponse);

  return userCardResponse;
}

Immutability

final User joao = new User("João", "joao@gmail.com");
public class User {
    private final String name;
    private final String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    
    ...
}
  • immutables/immutables
  • rzwitserloot/lombok

Tools

Declarative

vs

Imperative Programming

Parallel Processing

Referências

Obrigado!

Programação Funcional Java

By Rafael Nunes Vieira

Programação Funcional Java

  • 334