Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

O que a de errado com a minha regra de três?

Olá,

Me falaram que a maneira mais fácil de aprender java é programando em java. Então eu resolvi montar um timer. Muito provavelmente deve existir alguma classe pra isso (se me falar eu agradeço =). Mas como era só pra praticar mesmo eu fiz o seguinte código:

public class Darts {

    public static void main (String[] args) throws Exception {
        int minutos = 1;
        long tempoInicial = System.currentTimeMillis();
        long tempoFinal = tempoInicial + minutosParaMilisegundos(minutos);

        for (long i = tempoInicial; i < tempoFinal; i += 1000) {
            esperae(1000);
            p(regraDeTres(90,100)); // Aqui retorna o certo (90.0)%
            p(regraDeTres(i,tempoFinal)); // Aqui retorna sempre (99.0)%
        }

        p("=)");
    }

    private static void esperae(long miliseg) {
        long tempoAtual = System.currentTimeMillis();
        long tempoDesejado = tempoAtual + miliseg;

        while(tempoAtual < tempoDesejado){    
            tempoAtual = System.currentTimeMillis();
        }        
    }

    private static long minutosParaMilisegundos(int minutos) {
        return minutos * 60 * 1000;
    }

    private static double milisegundosParaMinutos(long miliseg) {
        if (miliseg <= 0)
            return 0;
        return (miliseg / 60) / 1000;
    }

    private static double regraDeTres(long milisegAtual, long milisegFinal) {
        return (milisegAtual * 100) / milisegFinal;
    }

    private static void p(Object print) {
        System.out.println(print);
    }
}

Eu só queria saber porque na primeira vez o meu método regraDeTres() retorna o que deveria e na segunda não.

1 resposta
solução!

Então a lógica do seu método "regraDeTres()" está correta, o que ocorre aqui é que quando você chama o método "System.currentTimeMillis()" o valores retornado não é zero, e sim um valor gigantesco, e quando adicionamos 60000 (equivalente a 1 minuto em milissegundo), o valor adicionado é insignificante em comparação ao seu total (representando menos de 1% do montante), sendo assim o valor de "i" será 99% em relação ao valor de "tempoFinal" até atingir os 100% após os 60 segundos. Mas eu creio que entendi seu objetivo, creio que o objetivo do código era saber quantos % do 1 minuto já foram passados a cada 1 segundo, sendo assim a solução seria alterar os parâmetros passados no método "regraDeTres" gerando um código semelhante a esse:

public class Darts {

    public static void main (String[] args) throws Exception {
        int minutos = 1;
        long tempoInicial = System.currentTimeMillis();
        long tempoASerPassado = minutosParaMilisegundos(minutos);
        long tempoFinal = tempoInicial + tempoASerPassado;

        for (long i = tempoInicial; i < tempoFinal; i += 1000) {
            esperae(1000);
            p(regraDeTres((i - tempoInicial), tempoASerPassado)); // i - tempoInicial = milisegundos passados até o momento.
        }

        System.out.println("=)");
    }

    private static void esperae(long miliseg) {
        long tempoAtual = System.currentTimeMillis();
        long tempoDesejado = tempoAtual + miliseg;

        while(tempoAtual < tempoDesejado){    
            tempoAtual = System.currentTimeMillis();
        }        
    }

    private static long minutosParaMilisegundos(int minutos) {
        return minutos * 60 * 1000;
    }

    private static double regraDeTres(long milisegAtual, long milisegFinal) {
        return (milisegAtual * 100) / (double) milisegFinal; // É necessário ter um dos lados da operação como Double para obtermos um resultado mais preciso.
    }

    private static void p(Object print) {
        System.out.printf("%.2f %% %n",print); // Formata para printar somente as 2 primeiras casas depois da virgula arredondando o valor
    }
}

E respondendo a sua pergunta, existem sim algumas classes do java que já fazem algo semelhante, um exemplo delas são as classes java.util.Timer e java.util.TimerTask que surtem o mesmo efeito no código a seguir:

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

public class Darts {

    public static void main (String[] args) throws Exception {
        int tempoASerPassado = 60000;
        int intervalo = 1000;
        int delay = 0;

        AtomicInteger tempoPassado = new AtomicInteger(0);

        Timer timer = new Timer();
        TimerTask tarefa = new TimerTask() {
            @Override
            public void run() {
                if (tempoPassado.get() <= tempoASerPassado) {
                    p(regraDeTres((tempoPassado.getAndAdd(intervalo)), tempoASerPassado));
                } else {
                    System.out.println("=)");
                    timer.cancel();
                }
            }
        };

        timer.schedule(tarefa, delay, intervalo);


    }    

    private static double regraDeTres(long milisegAtual, long milisegFinal) {
        return (milisegAtual * 100) / (double) milisegFinal; // É necessário ter um dos lados da operação como Double para obtermos um resultado mais preciso.
    }

    private static void p(Object print) {
        System.out.printf("%.2f %% %n",print); // Formata para printar somente as 2 primeiras casas depois da virgula arredondando o valor
    }

}