Skip to content

dearrudam/99DiasDeJava

Repository files navigation

99 Dias de Java

99 dias de conteúdo Java com o propósito de aprender e praticar! Bora praticar e aprender juntos? :)

Qualquer dúvida, sugestão e críticas, por favor, entre em contato:

url?color=%231DA1F2&label=maxdearruda&logo=twitter&logoColor=%231DA1F2&style=flat&url=https%3A%2F%2Ftwitter

Dia 01 - Modelando com Java: Representando números racionais

package noventaenovediasdejava.dia01;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class NumeroRacionalTest {
    @Test
    void test() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual á 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }
}
package noventaenovediasdejava.dia01;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual à 0");
        }
    }
}

Dia 02 - Modelando com Java: Sobrescrevendo metódos Java

package noventaenovediasdejava.dia02;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

}
package noventaenovediasdejava.dia02;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {
    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }
}

Dia 03 - Vamos representar números racionais em sua forma irredutível com Java!

package noventaenovediasdejava.dia03;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

    public NumeroRacional formaIrredutivel() {
        int numero = Math.abs(this.numerador);
        int maximoDivisorComum = Math.abs(this.denominador);
        int resto = 0;
        do {
            if (resto != 0) {
                numero = maximoDivisorComum;
                maximoDivisorComum = resto;
            }
            resto = numero % maximoDivisorComum;
        } while (resto != 0);
        return new NumeroRacional(
            this.numerador / maximoDivisorComum,
            this.denominador / maximoDivisorComum
        );
    }
}
package noventaenovediasdejava.dia03;

import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {
    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }

    @ParameterizedTest(name = "[{index}] a forma irredutível de {0} deve ser igual a {1}")
    @MethodSource("testarFormaIrredutivelArgs")
    void testarFormaIrredutivel(
        final NumeroRacional numeroRacionalBase,
        final NumeroRacional numeroRacionalNaFormaIrredutivelEsperado
    ) {
        final NumeroRacional numeroRacionalNaFormaIrredutivel = numeroRacionalBase
            .formaIrredutivel();
        Assertions.assertNotNull(
            numeroRacionalNaFormaIrredutivel,
            "não deve ser retornado valor/referência nulo"
        );
        Assertions.assertEquals(
            numeroRacionalNaFormaIrredutivelEsperado,
            numeroRacionalNaFormaIrredutivel
        );
    }

    static Stream<Arguments> testarFormaIrredutivelArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(12,4),
                new NumeroRacional(3,1)
            ),
            Arguments.arguments(
                new NumeroRacional(130,78),
                new NumeroRacional(5,3)
            ),
            Arguments.arguments(
                new NumeroRacional(-130,78),
                new NumeroRacional(-5,3)
            ),
            Arguments.arguments(
                new NumeroRacional(130,-78),
                new NumeroRacional(5,-3)
            )
        );
    }
}

Dia 04 - Somando números racionais com Java!

package noventaenovediasdejava.dia04;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

    public NumeroRacional formaIrredutivel() {
        int numero = Math.abs(this.numerador);
        int maximoDivisorComum = Math.abs(this.denominador);
        int resto = 0;
        do {
            if (resto != 0) {
                numero = maximoDivisorComum;
                maximoDivisorComum = resto;
            }
            resto = numero % maximoDivisorComum;
        } while (resto != 0);
        return new NumeroRacional(
            this.numerador / maximoDivisorComum,
            this.denominador / maximoDivisorComum
        );
    }

    public NumeroRacional somar(final NumeroRacional numeroRacional) {
        //        N1   N2   N1*D2+N2*D1
        //        -- + -- = ----------- =
        //        D1   D2     D1 * D2
        int n1 = this.numerador;
        int d1 = this.denominador;
        int n2 = numeroRacional.numerador;
        int d2 = numeroRacional.denominador;
        final NumeroRacional resultado =
            new NumeroRacional(
                ((n1 * d2) + (n2 * d1)),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }
}
package noventaenovediasdejava.dia04;

import java.util.stream.Stream;
import noventaenovediasdejava.dia04.NumeroRacional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {
    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }

    @ParameterizedTest(name = "[{index}] a forma irredutível de {0} deve ser igual a {1}")
    @MethodSource("testarFormaIrredutivelArgs")
    void testarFormaIrredutivel(
        final NumeroRacional numeroRacionalBase,
        final NumeroRacional numeroRacionalNaFormaIrredutivelEsperado
    ) {
        final NumeroRacional numeroRacionalNaFormaIrredutivel = numeroRacionalBase
            .formaIrredutivel();
        Assertions.assertNotNull(
            numeroRacionalNaFormaIrredutivel,
            "não deve ser retornado valor/referência nulo"
        );
        Assertions.assertEquals(
            numeroRacionalNaFormaIrredutivelEsperado,
            numeroRacionalNaFormaIrredutivel
        );
    }

    static Stream<Arguments> testarFormaIrredutivelArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(12, 4),
                new NumeroRacional(3, 1)
            ),
            Arguments.arguments(
                new NumeroRacional(130, 78),
                new NumeroRacional(5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(-130, 78),
                new NumeroRacional(-5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(130, -78),
                new NumeroRacional(5, -3)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} + {1} = {2}")
    @MethodSource("testarSomarArgs")
    void testarSomar(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        final NumeroRacional resultadoAtual =
            numeroRacional01.somar(numeroRacional02);
        Assertions.
            assertNotNull(resultadoAtual,
                          "não deve retornar valor/referência nula");
        Assertions.
            assertEquals(
                resultadoEsperado,
                resultadoAtual
            );
    }

    static Stream<Arguments> testarSomarArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 2)
            ),
            Arguments.arguments(
                new NumeroRacional(2, 3),
                new NumeroRacional(3, 4),
                new NumeroRacional(17, 12)
            ),
            Arguments.arguments(
                new NumeroRacional(5, 3),
                new NumeroRacional(4, 12),
                new NumeroRacional(2, 1)
            )
        );
    }
}

Dia 05 - Modelando com Java: Representando números racionais

package noventaenovediasdejava.dia05;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

    public NumeroRacional formaIrredutivel() {
        int numero = Math.abs(this.numerador);
        int maximoDivisorComum = Math.abs(this.denominador);
        int resto = 0;
        do {
            if (resto != 0) {
                numero = maximoDivisorComum;
                maximoDivisorComum = resto;
            }
            resto = numero % maximoDivisorComum;
        } while (resto != 0);
        return new NumeroRacional(
            this.numerador / maximoDivisorComum,
            this.denominador / maximoDivisorComum
        );
    }

    public NumeroRacional somar(final NumeroRacional numeroRacional) {
        //        N1   N2   N1*D2+N2*D1
        //        -- + -- = ----------- =
        //        D1   D2     D1 * D2
        int n1 = this.numerador;
        int d1 = this.denominador;
        int n2 = numeroRacional.numerador;
        int d2 = numeroRacional.denominador;
        final NumeroRacional resultado =
            new NumeroRacional(
                ((n1 * d2) + (n2 * d1)),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional subtrair(final NumeroRacional numeroRacional) {
//        N1   N2   N1*D2-N2*D1
//        -- - -- = ----------- =
//        D1   D2     D1 * D2
        int n1=this.numerador;
        int d1=this.denominador;
        int n2=numeroRacional.numerador;
        int d2=numeroRacional.denominador;

        final NumeroRacional resultado =
            new NumeroRacional(
                (n1*d2 - n2*d1),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }
}
package noventaenovediasdejava.dia05;

import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {
    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }

    @ParameterizedTest(name = "[{index}] a forma irredutível de {0} deve ser igual a {1}")
    @MethodSource("testarFormaIrredutivelArgs")
    void testarFormaIrredutivel(
        final NumeroRacional numeroRacionalBase,
        final NumeroRacional numeroRacionalNaFormaIrredutivelEsperado
    ) {
        final NumeroRacional numeroRacionalNaFormaIrredutivel = numeroRacionalBase
            .formaIrredutivel();
        Assertions.assertNotNull(
            numeroRacionalNaFormaIrredutivel,
            "não deve ser retornado valor/referência nulo"
        );
        Assertions.assertEquals(
            numeroRacionalNaFormaIrredutivelEsperado,
            numeroRacionalNaFormaIrredutivel
        );
    }

    static Stream<Arguments> testarFormaIrredutivelArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(12, 4),
                new NumeroRacional(3, 1)
            ),
            Arguments.arguments(
                new NumeroRacional(130, 78),
                new NumeroRacional(5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(-130, 78),
                new NumeroRacional(-5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(130, -78),
                new NumeroRacional(5, -3)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} + {1} = {2}")
    @MethodSource("testarSomarArgs")
    void testarSomar(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        final NumeroRacional resultadoAtual =
            numeroRacional01.somar(numeroRacional02);
        Assertions.
            assertNotNull(resultadoAtual,
                          "não deve retornar valor/referência nula");
        Assertions.
            assertEquals(
                resultadoEsperado,
                resultadoAtual
            );
    }

    static Stream<Arguments> testarSomarArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 2)
            ),
            Arguments.arguments(
                new NumeroRacional(2, 3),
                new NumeroRacional(3, 4),
                new NumeroRacional(17, 12)
            ),
            Arguments.arguments(
                new NumeroRacional(5, 3),
                new NumeroRacional(4, 12),
                new NumeroRacional(2, 1)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} - {1} = {2}")
    @MethodSource("testarSubtrairArgs")
    void testarSubtrair(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ){
        Assertions.assertEquals(
            resultadoEsperado,
            numeroRacional01.subtrair(numeroRacional02)
        );
    }

    static Stream<Arguments> testarSubtrairArgs(){
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1,2),
                new NumeroRacional(3,4),
                new NumeroRacional(-1, 4)
            )
        );
    }

}

Dia 06 - Multiplicando nossas opções: Multiplicação entre números racionais com Java!

package noventaenovediasdejava.dia06;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

    public NumeroRacional formaIrredutivel() {
        int numero = Math.abs(this.numerador);
        int maximoDivisorComum = Math.abs(this.denominador);
        int resto = 0;
        do {
            if (resto != 0) {
                numero = maximoDivisorComum;
                maximoDivisorComum = resto;
            }
            resto = numero % maximoDivisorComum;
        } while (resto != 0);
        return new NumeroRacional(
            this.numerador / maximoDivisorComum,
            this.denominador / maximoDivisorComum
        );
    }

    public NumeroRacional somar(final NumeroRacional numeroRacional) {
        //        N1   N2   N1*D2+N2*D1
        //        -- + -- = ----------- =
        //        D1   D2     D1 * D2
        int n1 = this.numerador;
        int d1 = this.denominador;
        int n2 = numeroRacional.numerador;
        int d2 = numeroRacional.denominador;
        final NumeroRacional resultado =
            new NumeroRacional(
                ((n1 * d2) + (n2 * d1)),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional subtrair(final NumeroRacional numeroRacional) {
//        N1   N2   N1*D2-N2*D1
//        -- - -- = ----------- =
//        D1   D2     D1 * D2
        int n1=this.numerador;
        int d1=this.denominador;
        int n2=numeroRacional.numerador;
        int d2=numeroRacional.denominador;

        final NumeroRacional resultado =
            new NumeroRacional(
                (n1*d2 - n2*d1),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional multiplicar(
        final NumeroRacional numeroRacional
    ) {
        // (N1 * N2) / (D1 * D2)
        NumeroRacional resultado =
            new NumeroRacional(
                this.numerador * numeroRacional.numerador,
                this.denominador * numeroRacional.denominador
            );
        return resultado.formaIrredutivel();
    }
}
package noventaenovediasdejava.dia06;

import java.util.stream.Stream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {

    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }

    @ParameterizedTest(name = "[{index}] a forma irredutível de {0} deve ser igual a {1}")
    @MethodSource("testarFormaIrredutivelArgs")
    void testarFormaIrredutivel(
        final NumeroRacional numeroRacionalBase,
        final NumeroRacional numeroRacionalNaFormaIrredutivelEsperado
    ) {
        final NumeroRacional numeroRacionalNaFormaIrredutivel = numeroRacionalBase
            .formaIrredutivel();
        Assertions.assertNotNull(
            numeroRacionalNaFormaIrredutivel,
            "não deve ser retornado valor/referência nulo"
        );
        Assertions.assertEquals(
            numeroRacionalNaFormaIrredutivelEsperado,
            numeroRacionalNaFormaIrredutivel
        );
    }

    static Stream<Arguments> testarFormaIrredutivelArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(12, 4),
                new NumeroRacional(3, 1)
            ),
            Arguments.arguments(
                new NumeroRacional(130, 78),
                new NumeroRacional(5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(-130, 78),
                new NumeroRacional(-5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(130, -78),
                new NumeroRacional(5, -3)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} + {1} = {2}")
    @MethodSource("testarSomarArgs")
    void testarSomar(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        final NumeroRacional resultadoAtual =
            numeroRacional01.somar(numeroRacional02);
        Assertions.
            assertNotNull(
                resultadoAtual,
                "não deve retornar valor/referência nula"
            );
        Assertions.
            assertEquals(
                resultadoEsperado,
                resultadoAtual
            );
    }

    static Stream<Arguments> testarSomarArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 2)
            ),
            Arguments.arguments(
                new NumeroRacional(2, 3),
                new NumeroRacional(3, 4),
                new NumeroRacional(17, 12)
            ),
            Arguments.arguments(
                new NumeroRacional(5, 3),
                new NumeroRacional(4, 12),
                new NumeroRacional(2, 1)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} - {1} = {2}")
    @MethodSource("testarSubtrairArgs")
    void testarSubtrair(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        Assertions.assertEquals(
            resultadoEsperado,
            numeroRacional01.subtrair(numeroRacional02)
        );
    }

    static Stream<Arguments> testarSubtrairArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 2),
                new NumeroRacional(3, 4),
                new NumeroRacional(-1, 4)
            )
        );
    }

    @ParameterizedTest(name = "[{index}]{0} * {1} = {2}")
    @MethodSource("testarMultiplicacaoArgs")
    void testarMultiplicacao(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ){
        Assertions
            .assertEquals(resultadoEsperado,
                          numeroRacional01.multiplicar(numeroRacional02)
            );
    }

    static Stream<Arguments> testarMultiplicacaoArgs(){
        return Stream.of(
          Arguments.arguments(
              new NumeroRacional(2,3),
              new NumeroRacional(6,6),
              new NumeroRacional(2,3)
          )
        );
    }

}

Dia 07 - Dividir para conquistar: Divisão entre números racionais com Java!

package noventaenovediasdejava.dia07;

public record NumeroRacional(Integer numerador, Integer denominador) {
    public NumeroRacional {
        if (numerador == null) {
            throw new IllegalArgumentException("numerador não pode ser nulo");
        }
        if (denominador == null) {
            throw new IllegalArgumentException("denominador não pode ser nulo");
        }
        if (Integer.valueOf(0).equals(denominador)) {
            throw new IllegalArgumentException("denominador não pode ser igual a 0");
        }
    }

    @Override
    public String toString() {
        return "%s/%s".formatted(this.numerador, this.denominador);
    }

    public NumeroRacional formaIrredutivel() {
        int numero = Math.abs(this.numerador);
        int maximoDivisorComum = Math.abs(this.denominador);
        int resto = 0;
        do {
            if (resto != 0) {
                numero = maximoDivisorComum;
                maximoDivisorComum = resto;
            }
            resto = numero % maximoDivisorComum;
        } while (resto != 0);
        return new NumeroRacional(
            this.numerador / maximoDivisorComum,
            this.denominador / maximoDivisorComum
        );
    }

    public NumeroRacional somar(final NumeroRacional numeroRacional) {
        //        N1   N2   N1*D2+N2*D1
        //        -- + -- = ----------- =
        //        D1   D2     D1 * D2
        int n1 = this.numerador;
        int d1 = this.denominador;
        int n2 = numeroRacional.numerador;
        int d2 = numeroRacional.denominador;
        final NumeroRacional resultado =
            new NumeroRacional(
                ((n1 * d2) + (n2 * d1)),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional subtrair(final NumeroRacional numeroRacional) {
        //        N1   N2   N1*D2-N2*D1
        //        -- - -- = ----------- =
        //        D1   D2     D1 * D2
        int n1 = this.numerador;
        int d1 = this.denominador;
        int n2 = numeroRacional.numerador;
        int d2 = numeroRacional.denominador;
        final NumeroRacional resultado =
            new NumeroRacional(
                (n1 * d2 - n2 * d1),
                (d1 * d2)
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional multiplicar(
        final NumeroRacional numeroRacional
    ) {
        // (N1 * N2) / (D1 * D2)
        NumeroRacional resultado =
            new NumeroRacional(
                this.numerador * numeroRacional.numerador,
                this.denominador * numeroRacional.denominador
            );
        return resultado.formaIrredutivel();
    }

    public NumeroRacional dividir(final NumeroRacional numeroRacional) {
        // (N1*D2)/(N2*D1)
        NumeroRacional resultado =
            new NumeroRacional(
                this.numerador * numeroRacional.denominador,
                numeroRacional.numerador * this.denominador
            );
        return resultado.formaIrredutivel();
    }
}
package noventaenovediasdejava.dia07;

import java.util.stream.Stream;
import noventaenovediasdejava.dia07.NumeroRacional;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

@TestMethodOrder(OrderAnnotation.class)
class NumeroRacionalTest {
    @Test
    @Order(0)
    void testarInstanciacao() {
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, 0),
            "não deve aceitar denominador igual a 0"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(null, 1),
            "não deve aceitar numerador nulo"
        );
        Assertions.assertThrows(
            IllegalArgumentException.class,
            () -> new NumeroRacional(1, null),
            "não deve aceitar denominador nulo"
        );
    }

    @Test
    @Order(1)
    void testarToString() {
        var numeroRacional = new NumeroRacional(2, 3);
        Assertions.assertEquals("2/3", numeroRacional.toString());
    }

    @ParameterizedTest(name = "[{index}] a forma irredutível de {0} deve ser igual a {1}")
    @MethodSource("testarFormaIrredutivelArgs")
    void testarFormaIrredutivel(
        final NumeroRacional numeroRacionalBase,
        final NumeroRacional numeroRacionalNaFormaIrredutivelEsperado
    ) {
        final NumeroRacional numeroRacionalNaFormaIrredutivel = numeroRacionalBase
            .formaIrredutivel();
        Assertions.assertNotNull(
            numeroRacionalNaFormaIrredutivel,
            "não deve ser retornado valor/referência nulo"
        );
        Assertions.assertEquals(
            numeroRacionalNaFormaIrredutivelEsperado,
            numeroRacionalNaFormaIrredutivel
        );
    }

    static Stream<Arguments> testarFormaIrredutivelArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(12, 4),
                new NumeroRacional(3, 1)
            ),
            Arguments.arguments(
                new NumeroRacional(130, 78),
                new NumeroRacional(5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(-130, 78),
                new NumeroRacional(-5, 3)
            ),
            Arguments.arguments(
                new NumeroRacional(130, -78),
                new NumeroRacional(5, -3)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} + {1} = {2}")
    @MethodSource("testarSomarArgs")
    void testarSomar(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        final NumeroRacional resultadoAtual =
            numeroRacional01.somar(numeroRacional02);
        Assertions.
            assertNotNull(
                resultadoAtual,
                "não deve retornar valor/referência nula"
            );
        Assertions.
            assertEquals(
                resultadoEsperado,
                resultadoAtual
            );
    }

    static Stream<Arguments> testarSomarArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 4),
                new NumeroRacional(1, 2)
            ),
            Arguments.arguments(
                new NumeroRacional(2, 3),
                new NumeroRacional(3, 4),
                new NumeroRacional(17, 12)
            ),
            Arguments.arguments(
                new NumeroRacional(5, 3),
                new NumeroRacional(4, 12),
                new NumeroRacional(2, 1)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} - {1} = {2}")
    @MethodSource("testarSubtrairArgs")
    void testarSubtrair(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        Assertions.assertEquals(
            resultadoEsperado,
            numeroRacional01.subtrair(numeroRacional02)
        );
    }

    static Stream<Arguments> testarSubtrairArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 2),
                new NumeroRacional(3, 4),
                new NumeroRacional(-1, 4)
            )
        );
    }

    @ParameterizedTest(name = "[{index}]{0} * {1} = {2}")
    @MethodSource("testarMultiplicacaoArgs")
    void testarMultiplicacao(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        Assertions
            .assertEquals(
                resultadoEsperado,
                numeroRacional01.multiplicar(numeroRacional02)
            );
    }

    static Stream<Arguments> testarMultiplicacaoArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(2, 3),
                new NumeroRacional(6, 6),
                new NumeroRacional(2, 3)
            )
        );
    }

    @ParameterizedTest(name = "[{index}] {0} / {1} = {2}")
    @MethodSource("testarDividirArgs")
    void testarDividir(
        final NumeroRacional numeroRacional01,
        final NumeroRacional numeroRacional02,
        final NumeroRacional resultadoEsperado
    ) {
        Assertions.assertEquals(
            resultadoEsperado,
            numeroRacional01.dividir(numeroRacional02)
        );
    }

    static Stream<Arguments> testarDividirArgs() {
        return Stream.of(
            Arguments.arguments(
                new NumeroRacional(1, 2),
                new NumeroRacional(3, 4),
                new NumeroRacional(2, 3)
            )
        );
    }
}

Dia 08 - Jokenpô em Java!?

package noventaenovediasdejava.dia08;

public interface JogadorJokenpo {
}
package noventaenovediasdejava.dia08;

public class JogoJokenpo {
    public JogoJokenpo(
        final JogadorJokenpo jogador01,
        final JogadorJokenpo jogador02
    ) {
        if (jogador01 == null && jogador02 == null) {
            throw new IllegalArgumentException("jogadores não informados");
        }
        if (jogador01 != null && jogador02 == null) {
            throw new IllegalArgumentException("jogador 02 não informado");
        }
        if (jogador01 == null && jogador02 != null) {
            throw new IllegalArgumentException("jogador 01 não informado");
        }
    }
}
package noventaenovediasdejava.dia08;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class JogoJokenpoTest {
    @Test
    void naoDevePermitirInstanciacao() {
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(null, null),
                "não deve ser permitido a instanciação do jogo sem jogadores"
            );
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(new JogadorJokenpo() {
                }, null),
                "não deve ser permitido a instanciação do jogo só com o jogador 01"
            );
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(
                    null,
                    new JogadorJokenpo() {
                    }
                ),
                "não deve ser permitido a instanciação do jogo só com o jogador 02"
            );
    }
}

Dia 09 - Jokenpô em Java - Pedra, Papel ou Tesoura?

package noventaenovediasdejava.dia09;

public enum MovimentoJokenpo {
    PEDRA {
        @Override
        public boolean ganhaDe(final MovimentoJokenpo movimento) {
            return TESOURA.equals(movimento);
        }
    },
    PAPEL {
        @Override
        public boolean ganhaDe(final MovimentoJokenpo movimento) {
            return switch (movimento) {
                case PEDRA -> true;
                default -> false;
            };
        }
    },
    TESOURA {
        @Override
        public boolean ganhaDe(final MovimentoJokenpo movimento) {
            return PAPEL.equals(movimento);
        }
    };

    public abstract boolean ganhaDe(final MovimentoJokenpo movimento);
}
package noventaenovediasdejava.dia09;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

class MovimentoJokenpoTest {
    @Test
    void testeDeEstrutura() {
        final var values = MovimentoJokenpo.values();
        Assertions.assertEquals(
            3,
            values.length,
            "Só deve ter 3 tipos de movimentos Jokenpô"
        );
        Assertions.assertEquals("PEDRA", values[0].name());
        Assertions.assertEquals("PAPEL", values[1].name());
        Assertions.assertEquals("TESOURA", values[2].name());
    }

    @Test
    void testarComportamento() {
        Assertions.assertEquals(true,
                                MovimentoJokenpo.PAPEL
                                    .ganhaDe(MovimentoJokenpo.PEDRA));
        Assertions.assertEquals(true,
                                MovimentoJokenpo.PEDRA
                                    .ganhaDe(MovimentoJokenpo.TESOURA));
        Assertions.assertEquals(true,
                                MovimentoJokenpo.TESOURA
                                    .ganhaDe(MovimentoJokenpo.PAPEL));
    }
}

Dia 10 - Jokenpô em Java - Quem vencerá?

package noventaenovediasdejava.dia10;

@FunctionalInterface
public interface JogadorJokenpo {
    MovimentoJokenpo jogar();
}
package noventaenovediasdejava.dia10;

public record JogadaJokenpo(
    boolean acabouEmpatada,
    JogadorJokenpo vencedor,
    JogadorJokenpo perdedor
) {
}
package noventaenovediasdejava.dia10;

public class JogoJokenpo {
    private final JogadorJokenpo jogador01;
    private final JogadorJokenpo jogador02;

    public JogoJokenpo(
        final JogadorJokenpo jogador01,
        final JogadorJokenpo jogador02
    ) {
        if (jogador01 == null && jogador02 == null) {
            throw new IllegalArgumentException("jogadores não informados");
        }
        if (jogador01 != null && jogador02 == null) {
            throw new IllegalArgumentException("jogador 02 não informado");
        }
        if (jogador01 == null && jogador02 != null) {
            throw new IllegalArgumentException("jogador 01 não informado");
        }
        this.jogador01 = jogador01;
        this.jogador02 = jogador02;
    }

    public JogadaJokenpo executarJogada() {
        MovimentoJokenpo movimentoJokenpo01 = this.jogador01.jogar();
        MovimentoJokenpo movimentoJokenpo02 = this.jogador02.jogar();
        if (movimentoJokenpo01.ganhaDe(movimentoJokenpo02)) {
            return new JogadaJokenpo(false, jogador01, jogador02);
        }
        if (movimentoJokenpo02.ganhaDe(movimentoJokenpo01)) {
            return new JogadaJokenpo(false, jogador02, jogador01);
        }
        return new JogadaJokenpo(true, null, null);
    }
}
package noventaenovediasdejava.dia10;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class JogoJokenpoTest {
    @Test
    void naoDevePermitirInstanciacao() {
        final JogadorJokenpo jogador = () -> null;
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(null, null),
                "não deve ser permitido a instanciação do jogo sem jogadores"
            );
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(jogador, null),
                "não deve ser permitido a instanciação do jogo só com o jogador 01"
            );
        Assertions
            .assertThrows(
                IllegalArgumentException.class,
                () -> new JogoJokenpo(
                    null, jogador
                ),
                "não deve ser permitido a instanciação do jogo só com o jogador 02"
            );
    }

    @Test
    void testeExecutarJogada() {
        JogadorJokenpo pietro = () -> MovimentoJokenpo.PEDRA;
        JogadorJokenpo max = () -> MovimentoJokenpo.TESOURA;
        JogoJokenpo jogo = Assertions
            .assertDoesNotThrow(
                () -> new JogoJokenpo(pietro, max),
                "deveria permitir a criação do Jogo"
            );
        JogadaJokenpo jogada = jogo.executarJogada();
        Assertions.assertEquals(
            false,
            jogada.acabouEmpatada()
        );
        Assertions.assertEquals(pietro, jogada.vencedor());
        Assertions.assertEquals(max, jogada.perdedor());
    }
}

Dia 11 - Jokenpô em Java - Implementando Jogadores: Rounding-Robin, Map, Reduce!?

package noventaenovediasdejava.dia11;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.stream.Collectors;

public class JogadorJokenpoRoundingRobin
    implements JogadorJokenpo {
    private final LinkedList<MovimentoJokenpo> movimentos;

    public JogadorJokenpoRoundingRobin() {
        this.movimentos = Arrays
            .stream(MovimentoJokenpo.values())
            .collect(Collectors.toCollection(LinkedList::new));
    }

    @Override
    public MovimentoJokenpo jogar() {
        synchronized (this){
            final var movimento = this.movimentos.poll();
            this.movimentos.add(movimento);
            return movimento;
        }
    }
}
package noventaenovediasdejava.dia11;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class JogadorJokenpoRoundingRobinTest {
    @Test
    void testeJogar() {
        JogadorJokenpo jogador = new JogadorJokenpoRoundingRobin();
        final var movimentosJogados =
            IntStream.range(0, 600) // criando um range de iteração de 0 à 599
                .boxed()
                .parallel()
                .map(i -> {
                    try{
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    var movimento = jogador.jogar();
                    try{
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    return Map.of(
                        String.valueOf(movimento),
                        new AtomicInteger(1));
                })
                .collect(Collectors.toList())
                .stream()
                .reduce(new HashMap<>(), (ac, item) -> {
                    item.entrySet()
                        .forEach(entry -> {
                            ac.computeIfAbsent(
                                entry.getKey(),
                                k -> new AtomicInteger(0)
                            )
                                .incrementAndGet();
                        });
                    return ac;
                });
        movimentosJogados
            .entrySet()
            .forEach(System.out::println);
        Assertions.assertEquals(
            Arrays
                .stream(MovimentoJokenpo.values())
                .map(String::valueOf)
                .sorted()
                .collect(Collectors.joining(",")),
            movimentosJogados
                .keySet()
                .stream()
                .map(String::valueOf)
                .sorted()
                .collect(Collectors.joining(",")),
            "tipos de movimentos fora do esperado"
        );
        Arrays.stream(MovimentoJokenpo.values())
            .forEach(movimento -> {
                Assertions.assertEquals(
                    200,
                    movimentosJogados.get(movimento.name()).get(),
                    "numero de jogadas com %s fora do esperado".formatted(movimento)
                );
            });
    }
}

Dia 12 - Jokenpô em Java - Implementando Jogadores: Jogador Randômico!?

package noventaenovediasdejava.dia12;

import java.util.Random;

public class JogadorJokenpoRandom implements JogadorJokenpo {
    @Override
    public MovimentoJokenpo jogar() {
        final var movimentosDisponiveis = MovimentoJokenpo.values();
        final int index = new Random().nextInt(movimentosDisponiveis.length);
        return movimentosDisponiveis[index];
    }
}
package noventaenovediasdejava.dia12;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class JogadorJokenpoRandomTest {
    @Test
    void testarJogar() {

        JogadorJokenpo jogador = new JogadorJokenpoRandom();

        final var movimentosExecutados =
            IntStream.range(0, 10)
                .boxed()
                .map(tentativa -> {
                    final var movimento = jogador.jogar();
                    System.out.println("%s = %s".formatted(tentativa, movimento));
                    return movimento;
                })
                .collect(Collectors.toList());

        Assertions.assertEquals(
            10,
            movimentosExecutados
                .stream()
                .filter(Objects::nonNull)
                .count(),
            "total de movimentos executados fora do esperado"
        );
    }
}

Dia 13 - Jokenpô em Java: CLI utilizando máquina de estado!

package noventaenovediasdejava.dia13;

import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicReference;

public class JogoJokenpoCLI {

    public static void main(String[] args) {
        EstadoDoJogo estadoAtual = new Inicio();
        while (estadoAtual.podeExecutar()) {
            estadoAtual = estadoAtual.executar(System.in, System.out);
            if (estadoAtual instanceof Sair sair) {
                sair.finalizarJogo(System.out);
            }
        }
    }

    static interface EstadoDoJogo {
        EstadoDoJogo executar(InputStream input, PrintStream output);
        default boolean podeExecutar() {
            return true;
        }
    }

    static class Inicio implements EstadoDoJogo {
        @Override
        public EstadoDoJogo executar(
            final InputStream input, final PrintStream output
        ) {
            output.println("Bem-vindo ao Jogo Jokenpô!!!");
            return new CapturarComandoPlayer01();
        }
    }

    static class CapturarComandoPlayer01 implements EstadoDoJogo {
        @Override
        public EstadoDoJogo executar(
            final InputStream input, final PrintStream output
        ) {
            output.println("Comandos válidos: SAIR, PEDRA, PAPEL ou TESOURA");
            var comando = new Scanner(input).next().trim();
            if ("SAIR".equalsIgnoreCase(comando)) {
                return new Sair();
            }
            final var movimentoDoPlayer01 =
                Arrays.stream(MovimentoJokenpo.values())
                    .filter(m -> m.name().equalsIgnoreCase(comando))
                    .findFirst();
            if (movimentoDoPlayer01.isEmpty()) {
                return new ComandoInvalido(this);
            }
            return new CapturarComandoPlayer02(movimentoDoPlayer01.get());
        }
    }

    static class CapturarComandoPlayer02 implements EstadoDoJogo {
        private final MovimentoJokenpo movimentoPlayer01;

        public CapturarComandoPlayer02(final MovimentoJokenpo movimentoPlayer01) {
            this.movimentoPlayer01 = movimentoPlayer01;
        }

        @Override
        public EstadoDoJogo executar(
            final InputStream input, final PrintStream output
        ) {
            final AtomicReference<MovimentoJokenpo> movimentoCPU = new AtomicReference<>();
            JogadorJokenpo player01 = () -> this.movimentoPlayer01;
            JogadorJokenpo player02 = () -> {
                movimentoCPU.set(new JogadorJokenpoRandom().jogar());
                return movimentoCPU.get();
            };
            JogoJokenpo jogoJokenpo =
                new JogoJokenpo(player01, player02);
            final var jogada = jogoJokenpo.executarJogada();
            if (jogada.acabouEmpatada()) {
                output.println("Quase!!! Deu empate!!!");
            } else if (Objects.equals(player01, jogada.vencedor())) {
                output.println("Wow!!! Você ganhou!!!");
            } else {
                output.println("Oh no!!! Você perdeu !!!");
            }
            output.println("CPU jogou: %s\n".formatted(movimentoCPU.get()));
            return new CapturarComandoPlayer01();
        }
    }

    static class ComandoInvalido implements EstadoDoJogo {
        private final EstadoDoJogo estadoDoJogo;

        public ComandoInvalido(final EstadoDoJogo estadoDoJogo) {
            this.estadoDoJogo = estadoDoJogo;
        }

        @Override
        public EstadoDoJogo executar(
            final InputStream input, final PrintStream output
        ) {
            output.println("Ops!!! Comando inválido!!! Tente novamente!!!");
            return this.estadoDoJogo;
        }
    }

    static class Sair implements EstadoDoJogo {
        @Override
        public EstadoDoJogo executar(final InputStream input, final PrintStream output) {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean podeExecutar() {
            return false;
        }

        public void finalizarJogo(final PrintStream output) {
            output.println("Fim de jogo!!!");
        }
    }
}

Dia 14 - Contador que não sabe contar! Classes Thread-safe

package noventaenovediasdejava.dia14;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(OrderAnnotation.class)
public class ContadorTest {
    @Test
    @Order(1)
    void testarContadorUnsafe() throws InterruptedException {
        testar(
            new ContadorUnsafe(),
            50,
            1000,
            (contador, numeroDeTarefas) ->
                Assertions.assertNotEquals(numeroDeTarefas, contador.getValor())
        );
    }

    @Test
    @Order(2)
    void testarContadorSafe01() throws InterruptedException {
        testar(
            new ContadorSafe01(),
            50,
            1000,
            (contador, numeroDeTarefas) ->
                Assertions.assertEquals(numeroDeTarefas, contador.getValor())
        );
    }

    @Test
    @Order(3)
    void testarContadorSafe02() throws InterruptedException {
        testar(
            new ContadorSafe02(),
            50,
            1000,
            (contador, numeroDeTarefas) ->
                Assertions.assertEquals(numeroDeTarefas, contador.getValor())
        );
    }

    @Test
    @Order(4)
    void testarContadorSafe03() throws InterruptedException {
        testar(
            new ContadorSafe03(),
            50,
            1000,
            (contador, numeroDeTarefas) ->
                Assertions.assertEquals(numeroDeTarefas, contador.getValor())
        );
    }

    private void testar(
        final Contador contador,
        final int numeroDeThreads,
        final int numeroDeTarefas,
        final BiConsumer<Contador, Integer> asserts
    ) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(numeroDeThreads);
        CountDownLatch countDownLatch = new CountDownLatch(numeroDeTarefas);
        for (int tarefas = 0; tarefas < numeroDeTarefas; tarefas++) {
            executorService.execute(() -> {
                try {
                    Thread.sleep(50);
                    contador.incrementar();
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        executorService.shutdown();
        countDownLatch.await(1, TimeUnit.MINUTES);
        asserts.accept(contador, numeroDeTarefas);
    }

    static interface Contador {
        void incrementar();
        int getValor();
    }

    static class ContadorUnsafe implements Contador {
        private int valor;

        @Override
        public void incrementar() {
            this.valor++; // this.valor = this.valor + 1
        }

        @Override
        public int getValor() {
            return this.valor;
        }
    }

    static class ContadorSafe01 implements Contador {
        private int valor;

        @Override
        public synchronized void incrementar() {
            this.valor++; // this.valor = this.valor + 1
        }

        @Override
        public synchronized int getValor() {
            return this.valor;
        }
    }

    static class ContadorSafe02 implements Contador {
        private int valor;

        @Override
        public void incrementar() {
            synchronized (this) {
                this.valor++; // this.valor = this.valor + 1
            }
        }

        @Override
        public int getValor() {
            synchronized (this) {
                return this.valor;
            }
        }
    }

    static class ContadorSafe03 implements Contador {
        private AtomicInteger valor = new AtomicInteger(0);

        @Override
        public void incrementar() {
            this.valor.incrementAndGet();
        }

        @Override
        public int getValor() {
            return this.valor.get();
        }
    }
}

Dia 15 - Criando um validador com Bean Validation!

  • adicionando dependências

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <!-- omitted -->
  <dependencies>
    <dependency>
      <groupId>javax.validation</groupId>
      <artifactId>validation-api</artifactId>
      <version>2.0.1.Final</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.13.Final</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.el</artifactId>
      <version>3.0.0</version>
    </dependency>
  </dependencies>
  <!-- omitted -->
</project>
  • exemplo de implementação

package noventaenovediasdejava.dia15;

import java.time.LocalDate;

@PeriodoValido
public record Periodo(LocalDate inicio, LocalDate fim) {
    public static Periodo of(LocalDate inicio, LocalDate fim) {
        return new Periodo(inicio, fim);
    }
}
package noventaenovediasdejava.dia15;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = PeriodoValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PeriodoValido {

    String message() default "período está inválido";

    Class<? extends Payload>[] payload() default {};

    Class<?>[] groups() default {};
}
package noventaenovediasdejava.dia15;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class PeriodoValidator implements ConstraintValidator<PeriodoValido, Periodo> {
    @Override
    public boolean isValid(Periodo value, ConstraintValidatorContext context) {
        if (value == null) {
            return false;
        }
        if (value.inicio() == null) {
            return false;
        }
        if (value.fim() == null) {
            return false;
        }
        return value.inicio().isBefore(value.fim())
                || value.inicio().isEqual(value.fim());
    }
}
package noventaenovediasdejava.dia15;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import javax.validation.Validation;
import javax.validation.Validator;
import java.time.LocalDate;

public class PeriodoTest {

    @Test
    @DisplayName("dado um periodo válido, o validator não deve encontrar violações")
    public void test01() {

        var violacoes = getValidator()
                .validate(Periodo.of(LocalDate.of(2022, 1, 1), LocalDate.now()));

        Assertions.assertTrue(violacoes.isEmpty());

    }

    @Test
    @DisplayName("dado um periodo inválido, o validator deve encontrar uma violação")
    public void test02() {

        var violacoes = getValidator()
                .validate(Periodo.of(LocalDate.now(), LocalDate.of(2022, 1, 1)));

        Assertions.assertFalse(violacoes.isEmpty());

    }

    public Validator getValidator() {
        return Validation.buildDefaultValidatorFactory().getValidator();
    }

}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages