Somando valores BigDecimal mas entre os valores pode exitir alguns valores definidos com null

Ola pessoal Boa Noite.

estou com o seguinte problema, estou desenvolvendo um relatório no iReport, cujo, já fiz o Select para pegar valores, somando de todos os meses, mas acontece que pode vir algum mês sem valor.

E eu tenho que fazer um total de atendimento por Meses (Jan, Fev…), também o total de atendimento por projeto.

Alguem sabe como resolver de maneira mais simples o seguinte problema?

[code]package br.teste;

import java.math.BigDecimal;

public class TesteTime {

public static void main(String[] args) {

	BigDecimal v1 = new BigDecimal(10);
	BigDecimal v2 = new BigDecimal(20);
	BigDecimal v3 = null;
	
	BigDecimal soma = v1.add(v2.add(v3));
	
	System.out.println(soma);
}

}[/code]

Eu estou com uma ídeia aqui, ainda não testei. mas parece ser meio grotesca sair testando tudo antes de soma.
Mas não acho que sejá a mais viavel.

Se alguem souber como resolver esse problema desses bentidos null que possam aparecer, ficarei muito agradecido

Obrigado a todos
att

Romildo Paiter

Porque você não coloca estes BigDecimals em um array e valida os elementos deste? Caso seja nulo crie uma nova instância com 0.

Se null é a mesma coisa que zero para você, crie um método que receba um BigDecimal (que pode ser null) e retorne o próprio BigDecimal, se não for null, ou BigDecimal.ZERO, se for null.

vai ter de faze verificação antes de usar o método.

faz um método set que verifique se o valor do objeto é null e se esta condição for verdadeira ele seta BigDecimal.ZERO

Bom pessoal, essa era a minha ideia e meu medo. E parece que tudo se realizou.

Muito Obrigado a todos.

Att

Romildo Jozue Paiter

Bom não sei o quão gambiarra é minha solução, mas por que você não faz um BigDecimal especial que herda de Big Decimal?

Resumidamente seria algo assim:

[code]
public class BigDecimalEspecial extends BigDecimal {

public BigDecimalEspecial(String val) {
	super(val);

}

@Override
public BigDecimal add(BigDecimal augend) {
	if (augend != null){
		return super.add(augend);
	}
	return super.add(BigDecimal.ZERO); //valor nulo
}	

}[/code]

ok?

Cara muito legal a sua solução.

Muito bem pensada. o maior problema é que vou ter que usar isso no iReport. Estou pesquisando se no iReport, tem como eu fazer essa soma sem ter que fazer alguma gambiara.

Sei que ele faz. Pois se vc somar de diferentes linha ele traz o resultado correto. Mas eu estou somando o conteúdo dos 12 meses do ano tudo em uma unica linha, até já tentei traz direto do banco a soma.

No MYSQL, ele não reconheceu as colunas com que vem com o nome AS JANEIRO,

Eu coloquei na consulta.
,
(JANEIRO + FEVEREIRO + MARCO…) MAS O MYSQL DIZIA QUE CAMPO DESCONHECIDO.

Valeu ai…

Tendo em mãos o mesmo problema, criei um método em minha classe utilitária assim:

Obs: Pode-se fazer de maneira semelhante para subtração, multiplicação, divisão… Postarei apenas a adição, mas caso precise das outras, só falar que eu posto com as outras operações.

	/**
	 * Método que soma os BigDecimals passados como parâmetros, tratando os nulos como 0 (Zero).
	 * @param args
	 * @return
	 */
	public static BigDecimal somar( BigDecimal ... args ) {
		
		BigDecimal resultado = BigDecimal.ZERO;
		
		for (int i = 0; i < args.length; i++) {
			resultado = resultado.add( args[ i ] == null ? BigDecimal.ZERO : args[ i ] );
		}
		
		return resultado;

	}

Como utilizar:

	public static void main( String[] args ) {
		BigDecimal vl1 = new BigDecimal( 1 );
		BigDecimal vl2 = null;
		BigDecimal vl3 = new BigDecimal( 1 );

		System.out.println( Utils.somar( vl1, vl2, vl3 )  );
	}

Desta maneira você poderá somar quantos BigDecimals vc quiser, basta ir passando eles via parâmetro.

Renan, acho mais seguro criar o bigDecimal passando uma string ao invés de um valor:

fiz um código que aceita Number, ou seja qualquer tipo de número, e mesmo assim mantém a precisão:

[code]public static void main(String[] args) {

	BigDecimal resultado = new BigDecimal(10);
	
	System.out.println(somar(resultado,10.8f)); //float
	System.out.println(somar(resultado,5.8d)); // double
	System.out.println(somar(resultado,5.8d)); // Integer
	System.out.println(somar(resultado,0.35)); // float
	
	//System.out.println(new BigDecimal(0.35));
	//0.34999999999999997779553950749686919152736663818359375 (quando não se converte em string, o erro do seu código)

}

public static BigDecimal somar(BigDecimal resultado, Number valor) {

    return valor == null ? resultado : resultado.add(new BigDecimal(valor.toString()));
    //maior flexibilidade.

}[/code]

Não entendi.

Esta falando do parâmetro passado no construtor no exemplo de utilização do método? Se sim, foi só um exemplo mesmo, pois no meu caso eu resgato esses valores diretamente do banco utilizando JPA e só trabalho com BigDecimal mesmo (nao fico convertendo de String pra BigDecimal, Int para BigDecimal e etc…).

[quote=R3N4N]Não entendi.

Esta falando do parâmetro passado no construtor no exemplo de utilização do método? Se sim, foi só um exemplo mesmo, pois no meu caso eu resgato esses valores diretamente do banco utilizando JPA e só trabalho com BigDecimal mesmo (nao fico convertendo de String pra BigDecimal, Int para BigDecimal e etc…).[/quote]

testa esse código usando seu método de somar:

[code]public static void main( String[] args ) {
BigDecimal vl1 = new BigDecimal( 0.35 );
BigDecimal vl2 = null;
BigDecimal vl3 = new BigDecimal( 1 );

System.out.println( Utils.somar( vl1, vl2, vl3 )  );  

} [/code]

O resultado foi: 1.34999999999999997779553950749686919152736663818359375

Caso vc queira arredondar o número é só utilizar o método da própria classe BigDecimal, por exemplo:
System.out.println( Utils.somar( vl1, vl2, vl3 ).setScale( 2, BigDecimal.ROUND_HALF_DOWN ) );
Retornando: “1.35”

Passei apenas um int pra exemplificar o uso da função. Mas se o problema é precisão, se construir o BigDecimal a partir de uma string ela será mantida como falado pelo Douglas. Mas não creio que esse seja o caso do tópico cujo o problema é somar 2 ou mais BigDecimals sendo que eles podem estar nulos (como eles foram construidos e seus problemas de precisão seria outro assunto) =D

De qualquer forma, abaixo 1 exemplo onde a precisão seria respeitada:

[code] public static void main( String[] args ) {
BigDecimal vl1 = new BigDecimal( “0.35” );
BigDecimal vl2 = null;
BigDecimal vl3 = new BigDecimal( 1 );

    System.out.println( Utils.somar( vl1, vl2, vl3 )  );   
}  [/code]

Além de que o problema de precisão não é exclusivo do BigDecimal, o buraco é mais em baixo:

System.out.println( 6 * 1.6 );

[quote=R3N4N]O resultado foi: 1.34999999999999997779553950749686919152736663818359375

Caso vc queira arredondar o número é só utilizar o método da própria classe BigDecimal, por exemplo:
System.out.println( Utils.somar( vl1, vl2, vl3 ).setScale( 2, BigDecimal.ROUND_HALF_DOWN ) );
Retornando: “1.35”
[/quote]

ok

Blz.

o iReport aceita programação Java, então vc pode testar pra ver se o valor é nulo antes de somar.

$F{valorBigDecimal} == null ? BigDecimal.ZERO : $F{valorBigDecimal}

Mais ainda acho mais correto fazer isso na aplicação, veja, acho que vc está usando um modelView certo?

se não estiver seu problema coemça aí. Com o modelView vc seta os valores sem se preocupar se são nulos ou não, depois de setar todos os valores faz um método que efetua a soma.

private void somaOsDozeMeses(MeuModelViewComOsDados modelView) { modelView.setValorTotal(modelView.getValorJaneiro().add(modelView.getValorFevereiro()).add(...)); }

e dentro do get do MeuModelViewComOsDados vc tem algo do tipo.

public BigDecimal getValorJaneiro() { return this.valorJaneiro == null ? BigDecimal.ZERO : this.valorJaneiro; }

Com isso vc garante que o valor sempre será válido pra soma. E mesmo que queira somar no iReport vai funcionar pois ele usar os getters do modelView.