Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Função Array<BigDecimal>.somatoria() em package diferente

Bom dia a todos

A função somatoria() recebe uma Array<BigDecimal> antes da função. Mas como eu faço quando o arquivo está em outra package, como chamá-lo?

Tentei de vários jeitos e não consegui: salario.somatoria(), salarioBigDecimal.salario.somatoria(), salarioBigDecimal.somatoria()

classes referidas:

    private val salarioBigDecimal = SalarioBigDecimal()
    private val salario = salarioBigDecimal.bigDecimalArrayOf("1500.80", "2050.09","8500.00", "3076.98","6780.00")

Código da classe do método:

package br.com.alura.arrays.salario

import java.math.BigDecimal
import java.math.MathContext

class SalarioBigDecimal {
    fun bigDecimalArrayOf(vararg valores:String): Array<BigDecimal>{
        return Array<BigDecimal>(valores.size){ i -> valores[i].toBigDecimal()}
    }
    fun calculaAumentoSalarial(salario: BigDecimal): BigDecimal {
        if (salario < "5000.00".toBigDecimal()) {
            return salario.add("500".toBigDecimal())
        }
        return salario.multiply("1.1".toBigDecimal()).round(MathContext.DECIMAL64).setScale(2)
    }
    fun Array<BigDecimal>.somatoria(): BigDecimal {
        return this.reduce{acumulador,valor -> acumulador+valor}
    }
}

classe de teste:

package br.com.alura.arrays.salario

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.MathContext

class SalarioBigDecimalTest{
    private val salarioBigDecimal = SalarioBigDecimal()
    private val salario = salarioBigDecimal.bigDecimalArrayOf("1500.80", "2050.09","8500.00", "3076.98","6780.00")
    private val salarioComAumento = salario.map {
            salario -> salarioBigDecimal.calculaAumentoSalarial(salario)
    }.toTypedArray()
    @Test
    fun testaArrayDeBigDecimal(){
        val salarios = Array<BigDecimal>(5) { BigDecimal.ZERO }
        salarios[0]= "1500.80".toBigDecimal()
        salarios[1]= "2050.09".toBigDecimal()
        kotlin.test.assertEquals("[1500.80, 2050.09, 0, 0, 0]", salarios.contentToString())
    }
    @Test
    fun testaArrayDeBigDecimalComFuncao() {
        kotlin.test.assertEquals("[1500.80, 2050.09, 8500.00, 3076.98, 6780.00]", salario.contentToString())
    }
    @Test
    fun testaMapdeArray(){
        kotlin.test.assertEquals(
            "[2000.80, 2550.09, 9350.00, 3576.98, 7458.00]",
            salarioComAumento.contentToString()
        )
    }
    @Test
    fun testaSomatoriaComReduce(){
        kotlin.test.assertEquals("21907.87".toBigDecimal(), salario.somatoria())
    }
    @Test
    fun testaSomatoriaComReduceDepoisDoAumento(){
        kotlin.test.assertEquals("24935.87".toBigDecimal(), salarioComAumento.somatoria())
    }
    @Test
    fun testaSomatoriaComFold(){
        val gastoInical = salarioComAumento.somatoria()
        val gastoTotal = salarioComAumento.fold(gastoInical) { acumulador, salario ->
            acumulador + (salario.multiply
                (6.toBigDecimal())).round(MathContext.DECIMAL64).setScale(2)
        }
        kotlin.test.assertEquals("174551.09".toBigDecimal(), gastoTotal)
    }
    @Test
    fun ordenaListaDeSalario(){
        val salarioOrdenado = salarioComAumento.sorted().asReversed()
        kotlin.test.assertEquals("[9350.00, 7458.00, 3576.98, 2550.09, 2000.80]", salarioOrdenado.toString())
    }
}

Ps: para o código dar certo, tive que voltar o somatoria() para o arquivo de teste

6 respostas

Para chamar a função somatoria() de outra classe, é necessário utilizar a notação de ponto (.) para indicar que a função está sendo chamada em um objeto da classe Array. Assim, no caso apresentado, para chamar a função somatoria() da classe SalarioBigDecimal a partir da classe de teste, seria necessário criar um objeto da classe Array a partir da lista salario e, em seguida, chamar a função somatoria() utilizando a notação de ponto. Dessa forma, a chamada ficaria da seguinte forma:

`val salarioBigDecimal = SalarioBigDecimal()

val salario = salarioBigDecimal.bigDecimalArrayOf("1500.80", "2050.09","8500.00", "3076.98","6780.00")

val arraySalario = salario.toTypedArray() val somatoria = arraySalario.somatoria()

println(somatoria) `

Onde arraySalario é o objeto da classe Array<BigDecimal> criado a partir da lista salario, e somatoria é a variável que armazena a soma dos elementos do array. Note que foi necessário converter a lista salario para um array para poder utilizar a função somatoria().

É importante também que a classe que contém a função somatoria() esteja sendo importada corretamente na classe de teste. Para isso, basta adicionar a seguinte linha de código no início da classe de teste:

`import br.com.alura.arrays.salario.SalarioBigDecimal

` Assim, a classe de teste reconhecerá a classe SalarioBigDecimal e poderá chamar a função somatoria() corretamente.

Link do meu LinkedIn:https://www.linkedin.com/in/eduardo-a-querido-dias-logistica/

Não estou conseguindo fazer funcionar a partir sua explicação:

  1. A array salario é do tipo Array e não tem como converter por meio do val arraySalario = salario.toTypedArray()
  2. não é póssível fazer o link do array salario com a função somaria: val somatoria = arraySalario.somatoria(), devido a somatoria() ser da classe SalarioBigDecimal
  3. O importe import br.com.alura.arrays.salario.SalarioBigDecimal é desnecessária, ja que a classe SalarioBigDecimalTest é uma classe de teste da SalarioBigDecimal, e não precisa de importe do mesmo

Você poderia, por favor, me mostrar o código mais completo para mostrar melhor a solução desse problema?

Bom dia Murilo Vamos tentar outra abordagem.

Primeiro, você precisa tornar a função de extensão somatoria() visível na classe de teste, então mova a função para um arquivo separado e faça a importação na classe de teste.

Crie um novo arquivo chamado BigDecimalExtensions.kt no pacote br.com.alura.arrays.salario:

package br.com.alura.arrays.salario

import java.math.BigDecimal

fun Array<BigDecimal>.somatoria(): BigDecimal {
    return this.reduce { acumulador, valor -> acumulador + valor }
}

Agora, atualize a classe de teste para importar a função de extensão:

package br.com.alura.arrays.salario

import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.MathContext

class SalarioBigDecimalTest {
    private val salarioBigDecimal = SalarioBigDecimal()
    private val salario = salarioBigDecimal.bigDecimalArrayOf("1500.80", "2050.09", "8500.00", "3076.98", "6780.00")

    // Outros testes

    @Test
    fun testaSomatoriaComReduce() {
        kotlin.test.assertEquals("21907.87".toBigDecimal(), salario.somatoria())
    }
}

Neste exemplo, a função de extensão somatoria() foi movida para um arquivo separado e importada na classe de teste. Agora você pode chamar salario.somatoria() diretamente nos seus testes.

Espero que isso ajude a resolver o problema. Se você tiver mais dúvidas, por favor, sinta-se à vontade para perguntar.

Agradeço a sua atenção e sua paciência,mas eu já tinha feito algo parecido, colocando a função somatoria() e media() fora do método, e como a classe de teste importa automaticamente a classe original, deu certo. Classe de implementação:

package br.com.alura.arrays.salario
    //(imports)
class SalarioBigDecimal {
    //(outras funções)
}
//eles estão fora do salarioBigDecimal
fun Array<BigDecimal>.somatoria(): BigDecimal {
    return this.reduce{acumulador,valor -> acumulador+valor}
}
fun Array<BigDecimal>.media(): BigDecimal {
    if (this.isEmpty()){
        return BigDecimal.ZERO
    }
    return this.somatoria()/this.size.toBigDecimal()
}

classe de testes:

classe de teste:
package br.com.alura.arrays.salario

//não precisei de import da classe salarioBigDecimal
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.math.MathContext

class SalarioBigDecimalTest{

    private val salarioBigDecimal = SalarioBigDecimal()
    private val salario: Array<BigDecimal> = salarioBigDecimal.bigDecimalArrayOf("1500.80", "2050.09","8500.00", "3076.98","6780.00")
    private val salarioComAumento = salario.map {
            salario -> salarioBigDecimal.calculaAumentoSalarial(salario)
    }.toTypedArray()
       //(outros testes)
    @Test
    fun testaSomatoriaComReduce(){
        assertEquals("21907.87".toBigDecimal(), salario.somatoria())
    }
    @Test
    fun pegaOS3maioresSalariosEFazAMedia() {
        val tresMaioresSalarios = salarioComAumento.sorted().takeLast(3).toTypedArray()
        assertEquals("[3576.98, 7458.00, 9350.00]",tresMaioresSalarios.contentToString())
        assertEquals("6794.99".toBigDecimal(),tresMaioresSalarios.media())
    }
}

Mas o cerne da questão não é esse. O meu foco não é fazer esse código funcionar, o que eu quero saber é se é possivel eu colocar a função somatoria() e media() dentro de uma classe, e a partir de outro package acessá-lo.

Eu quero fazer isso para poder implementar esse tipo de função em um projeto que eu tenho (na versão 1.2, atualmente está em 1.1) e eu quero poder acessá-lo em vários lugares, sem estar limitado ao arquivo estar na mesma package

Ps: esse projeto é um gerenciador para o Rh de um time de futebol gerenciar os dados dos funcionários. Eu estou na versão 1.1 e pretendo na versão seguinte converte-lo de Java para Kotlin, além de implementar outras novidades que eu for aprendendo no curso de: "Linguagem Kotlin", "Kotlin e Spring Boot" e "Aprofunde em Kotlin e DevOps com uma aplicação Cloud Native". Link do projeto(versão 1.1)

solução!

Olá Murilo, entendi sua preocupação em relação à reutilização das funções de extensão em diferentes packages. Sim, é possível colocar as funções de extensão dentro de uma classe e acessá-las a partir de outro package. Para fazer isso, siga os passos abaixo:

Crie uma classe chamada BigDecimalOperations no pacote br.com.alura.arrays.salario e mova as funções de extensão para dentro dessa classe:

package br.com.alura.arrays.salario

import java.math.BigDecimal

class BigDecimalOperations {
    fun Array<BigDecimal>.somatoria(): BigDecimal {
        return this.reduce { acumulador, valor -> acumulador + valor }
    }

    fun Array<BigDecimal>.media(): BigDecimal {
        if (this.isEmpty()) {
            return BigDecimal.ZERO
        }
        return this.somatoria() / this.size.toBigDecimal()
    }
}

Em qualquer classe que desejar utilizar essas funções, instancie a classe BigDecimalOperations e utilize-a para chamar as funções de extensão:

import br.com.alura.arrays.salario.BigDecimalOperations

class OutraClasse {
    val bigDecimalOperations = BigDecimalOperations()
    val salario = arrayOf("1500.80", "2050.09", "8500.00", "3076.98", "6780.00").map { it.toBigDecimal() }.toTypedArray()

    fun exemplo() {
        val somatoria = bigDecimalOperations.run { salario.somatoria() }
        val media = bigDecimalOperations.run { salario.media() }

        println("Somatória: $somatoria")
        println("Média: $media")
    }
}

Note que utilizamos o método run para chamar as funções de extensão a partir do objeto bigDecimalOperations. Dessa forma, você pode acessar e utilizar as funções de extensão em diferentes packages sem problemas.

Espero que isso resolva sua dúvida. Se tiver mais perguntas ou precisar de mais esclarecimentos, por favor, sinta-se à vontade para perguntar.

Muito obrigado pela ajuda, dessa vez deu certo