搜索
首页Javajava教程项目挑战 - 创建计数器应用程序

我们已经完成了这个初始模块的第二个设计挑战,这是进入面向对象编程模块之前的最后一个任务。
我承认我发现这个挑战有点愚蠢,它可能是一个没有任何问题的代码挑战,但没关系。

建议的挑战:

系统必须通过终端接收两个参数,这两个参数代表两个整数,您必须通过这两个数字获取交互次数 (for) 并在控制台中打印递增的数字 (System.out.print),例如:

  • 如果您传递数字 12 和 30,那么我们将与 18 次出现的交互进行打印,例如:“打印数字 1”、“打印数字 2”等等。
  • 如果第一个参数大于第二个参数,则必须抛出名为 ParametrosInvalidosException 的自定义异常,并带有第二条消息:“第二个参数必须大于第一个”

建议步骤:

  1. 创建项目 DesafioControleFluxo
  2. 在项目中,创建 Contador.java 类来执行我们程序的所有编码。
  3. 在项目中,创建 ParametrosInvalidosException 类,它将代表系统中的业务异常。

如您所见,这并不是世界上最复杂的事情,但它开辟了一些有趣的可能性。
我们可以从最后开始并创建自定义异常(我的意思是,在创建项目之后,对吧):

//InvalidParametersException.java
public class InvalidParametersException extends Exception {  
    public InvalidParametersException() {  
        super();  
    }
}

这是定义自定义异常的最简单方法。我们创建一个类(并且按照命名模式,添加后缀 Exception),当它是受检查异常时,该类从 Exception 扩展;如果它不是受检查异常(非受检查异常),则从 RuntimeException 扩展。然后我们根据我们希望异常具有的 行为 定义类构造函数。在这种情况下,她不会做太多事情,所以我们要改进她。

哦卢卡斯,但是什么是类构造函数?你从来没有说过这件事!!1!

确实还没有提到什么是构造函数。下一个模块“面向对象”应该会纠正这个知识差距。控制住你的情绪,动物。

就我们的异常而言,我决定它必须是一个受检查的异常(即,必须在使用抛出它的方法时对其进行处理),以确保业务规则如果第一个参数大于对于第二个参数,您必须抛出名为 ParametrosInvalidosException 的自定义异常,并带有第二条消息:“第二个参数必须大于第一个” 受到尊重,并且存在错误处理,以免破坏应用程序

为了在处理时更加灵活,我们可以在异常中定义额外的构造函数,每个构造函数执行不同的操作:

// InvalidParametersException.java
public class InvalidParametersException extends Exception {  
    private static final String DEFAULT_MESSAGE = "Um ou mais argumentos são inválidos.";  

    public InvalidParametersException() {  
        super(DEFAULT_MESSAGE);  
    }  
    public InvalidParametersException(String message) {  
        super(message);  
    }  
    public InvalidParametersException(String message, Throwable cause) {  
        super(message, cause);  
    }  
    public InvalidParametersException(Throwable cause) {  
        super(DEFAULT_MESSAGE, cause);  
    }}

让我们冷静地看待这件事。
我们通过扩展 Exception 类来声明 InvalidParametersException 类。正如我上面提到的,这意味着任何调用抛出此异常的方法的类都需要对其进行处理。

接下来,我们声明常量 DEFAULT_MESSAGE,并为其分配“一个或多个参数无效。”。我们怎么知道它是一个常数?由于最后的保留字和 SCREAMING_SNAKE_CASE 的使用,这是指定常量的常见模式。如果抛出不带参数的异常(如第一个构造函数中所定义),则将显示此值:它调用超类构造函数(在本例中为 Exception)并传递 DEFAULT_MESSAGE。因此,如果我们有一个无效参数,如果未定义自定义消息,则显示的错误将是“一个或多个参数无效。”。

第二个构造函数允许使用自定义消息抛出异常。换句话说,我们可以用自定义消息替换标准错误消息。例如,我们可以显示 You指示我访问 null 的内容,而不是显示线程“main”java.lang.NullPointerException 之类的内容。朋友你还好吗?.

最后两个有不同的论点,原因。它是一个 Throwable(可抛出的),用于重新抛出异常。例如,假设在您的某些应用程序中,有一个点需要对用户输入的两个数据进行除法,分母(还记得分数类中的分母吗?)最终为 0。

Desafio de Projeto - Criando uma aplicação contadora

Lembra quando esse formato de meme era popular? Bons tempos aqueles...

Isso vai lançar uma ArithmeticException, mas o que você quer na verdade é usar sua exceção customizada novinha, que deu tanto duro para criar. Aí você pode fazer algo assim:

try {
    Scanner sc = new Scanner(System.in);
    int num1 = sc.nextInt(); //10
    int num2 = sc.nextInt(); //0
    int result = num1 / num2; //OH SHI-
} catch (ArithmeticException ex) {
    throw new InvalidParametersException("Não pode dividir por 0, bicho", ex);
}

Ou seja, o bloco try-catch captura a ArithmeticException, pega o motivo de ter sido lançada e passa para a exceção customizada, que vai disponibilizar uma mensagem mais amigável para o usuário E mostrar a causa dessa pataquada toda. A pilha de execução (stack trace) para essa situação poderia ser mais ou menos assim:

Exception in thread "main" InvalidParametersException: Não pode dividir por 0, bicho
    at Main.main(Main.java:10)  
    Caused by: java.lang.ArithmeticException: / by zero
        at Main.main(Main.java:9)

Desafio de Projeto - Criando uma aplicação contadora
Temos nossa mensagem amigável na primeira linha da pilha mas também temos o ponto exato onde as coisas deram errado, para termos uma depuração mais rápida.

Nossa, quanta coisa. E ainda nem entramos no método propriamente dito.
Aqui eu tenho que fazer uma mea-culpa: Eu reclamei a um tempo atrás de como na documentação da classe Scanner mostra que existe um método específico para capturar cada tipo primitivo e fui induzido a achar que esse era o único jeito de fazer isso. Mas conversando no Discord da Orange Juice, meu chegado Claudio me disse que tem um jeito muito mais simples:
Desafio de Projeto - Criando uma aplicação contadora
Ou seja, eu fiquei reclamando reclamando reclamando mas aparentemente dá pra fazer exatamente como no C#, como eu falei que era melhor. Claro, não dá pra aceitar tudo cegamente, então eu fui fazer um teste:

public static void main(String[] args) {  
    Scanner scanner = new Scanner(System.in);  
    System.out.print("Insira o primeiro número: ");  
    int num1 = Integer.parseInt(scanner.nextLine());  
    System.out.print("Insira o segundo número: ");  
    int num2 = Integer.parseInt(scanner.nextLine()); 

    System.out.println("O primeiro número foi: " + num1 + " e o segundo foi: " + num2);  
}

Desafio de Projeto - Criando uma aplicação contadora

Não é que deu certo, gente?
Eu to me sentindo bem mal agora, não fiz a coisa mais simples antes de começar a reclamar... Que burro, dá zero pra mim.
Desafio de Projeto - Criando uma aplicação contadora

Muito bem. Me desculpe, menino Java.
Isto posto, podemos começar a desenvolver nosso método de contagem. A classe Counter vai ter dois métodos: o counter, que vai conter a lógica da contagem e o main, que vai chamar o contador e tratar as exceções que surgirem. Vamos começar com o counter:

public class Counter {  
    public static void main(String[] args) {}  //por enquanto esse método segue vazio

    public static void count(int num1, int num2) throws InvalidParametersException {  
        if (num1  num2) throw new InvalidParametersException("O primeiro argumento deve ser maior que o segundo");  

        int counter = num2 - num1;  
        System.out.printf("Vou imprimir todos os números de 1 até %d.%n", counter);  

        for (int i = 1; i 



<p>Declaramos o método counter, que é público e não tem retorno (podemos ter certeza por conta do void ali). Além disso, esse método é estático, então não precisamos instanciar a classe para podermos usá-lo. Ele recebe dois argumentos do tipo int, num1 e num2 -- criatividade é a alma do negócio. Por fim, podemos ver que esse método lança a nossa maravilhosa exceção InvalidParametersException, o que vai obrigar o método main a realizar algum tipo de tratamento em cima dela.</p>

<p>Para garantir que as regras de negócio vão ser respeitadas, o método faz duas verificações: </p>

<ol>
<li>Checa se qualquer um dos números é negativo e, em caso positivo lança uma exceção informando ao usuário que um ou mais argumentos são inválidos;

<ul>
<li>Essa checagem, apesar de não ter sido pedida, é para garantir que não haveria resultados esquisitos na subtração feita. Eu não queria, por exemplo, ter que lidar com resultados negativos.</li>
</ul>
</li>
<li>Checa se o primeiro número é maior do que o segundo. Se sim, lança uma exceção orientando o usuário que o segundo número (o numerador da divisão) deve ser maior.</li>
</ol>

<p>Depois disso, é realizada a subtração que vai montar o <em>loop</em>. Feita essa conta, é impressa no console uma mensagem informando que a aplicação irá mostrar todos os números de 1 até o resultado. </p>

<p>E aqui vem mais uma particularidade do Java: a falta de interpolação de strings. Eu me acostumei a escrever<br>
</p>

<pre class="brush:php;toolbar:false">const variable = variable;
let sentence = `I'm a sentence that uses a ${variable}!`;

ou

string name = "John Doe";
string sentence = $"My name is {name}.";

que é até esquisito imaginar uma linguagem moderna que não utiliza isso.

Para ficar melhor (e evitar usar a concatenação com aquela sintaxe horrorosa), descobri que poderia formatar a mensagem com o método String.format(), da mesma forma que a formatação de string do C. E assim como no C, existe a possibilidade de já formatar a string usando o método print. Em vez de usar o .println() para imprimir uma string e já pular uma linha (o ln significa que caractere para newline será adicionado no final), o método .printf() formata a mensagem de acordo com o placeholder informado.
Existem muitos placeholders que podem ser utilizados, mas os mais comuns são %s para string, %d para int, %f para números de ponto flutuante (como double e float) e %f para data/hora. Porém esse método não cria uma quebra de linha então caso seja necessário, é preciso adicionar o caractere %n para uma nova linha.

Aí, por último, fazemos nosso laço for, sem grandes mistérios. Inicializamos o contador do loop em 1 e o instruímos a repetir a tarefa até o chegar no resultado final, incrementando o valor do contador de um em um. A cada volta imprimimos o valor do contador atual, cumprindo, desse modo, o requisito do desafio.

Beleza, criamos o método que vai realizar a ação que precisamos. Agora, o que falta é chamar a função e executá-la em algum lugar, né? Vamos fazer isso no método main da nossa classe Counter:

public class Counter {  
    public static void main(String[] args) {  
        try {  
            Scanner scanner = new Scanner(System.in);  
            System.out.println("Insira dois números e a aplicação imprimirá a diferença entre eles, linha a linha.");  
            System.out.print("Insira o primeiro número: ");  
            int num1 = Integer.parseInt(scanner.nextLine());  
            System.out.print("Insira o segundo número: ");  
            int num2 = Integer.parseInt(scanner.nextLine());  

            count(num1, num2);  

        } catch (InvalidParametersException e) {  
            System.out.println(e.getMessage());  
        }    
    }  
    public static void count(int num1, int num2) throws InvalidParametersException { /* lógica descrita acima */ }

Aqui não tem nada muito excepcional: Instanciamos um novo scanner e, seguindo a dica valiosa do Cláudio, pedimos ao usuário que insira dois números. Esses números são capturados como string e imediatamente convertidos em int. Com esses dados, chamamos a função count passando os dois números como parâmetros e, caso alguma exceção seja lançada, uma mensagem de erro será exibida no console.

Show, mas será que funciona?

Desafio de Projeto - Criando uma aplicação contadora
Desafio de Projeto - Criando uma aplicação contadora
Desafio de Projeto - Criando uma aplicação contadora

Aparentemente sim. ✌️
Mas o que acontece se, por exemplo, algum usuário espírito de porco curioso inserisse um número muito grande em um dos campos? Será que a aplicação daria conta do recado?
Desafio de Projeto - Criando uma aplicação contadora
Bom, não né. O int, destino da conversão da string nos inputs, aloca 32 bits de memória para cada variável. Isso quer dizer, na prática, que o valor máximo que ele pode armazenar é 2147483647 (e o menor, -2147483648). Quando o número alvo extrapola esse limite, essa exceção NumberFormatException é lançada.
Para solucionar isso, poderíamos mudar o tipo de destino de int para long, mas o problema da limitação ainda se mantém. Claro que é bem mais difícil que alguém indique um número grande como o long (cujo valor máximo é 9223372036854775807), mas é sempre bom não dar chance pro azar. Por isso, a melhor coisa é adicionar algum tipo de limitação e informar ao usuário que ele tá maluco precisa informar um número dentro do intervalo esperado.

Além disso, a aplicação encerrar quando encontra um erro é meio chato. O ideal seria que ela voltasse a iniciar caso encontrasse um erro, até que os inputs fossem inseridos de maneira correta.

Podemos resolver adicionando um novo catch no nosso try e envolvendo a aplicação toda em um laço while:

public class Counter {  
    public static void main(String[] args) {  
        while (true) {  
            try {  
                Scanner scanner = new Scanner(System.in);  
                System.out.println("Insira dois números e a aplicação imprimirá a diferença entre eles, linha a linha.");  
                System.out.print("Insira o primeiro número: ");  
                int num1 = Integer.parseInt(scanner.nextLine());  
                System.out.print("Insira o segundo número: ");  
                int num2 = Integer.parseInt(scanner.nextLine());  

                count(num1, num2);  
                break;  
            } catch (InvalidParametersException e) {  
                System.out.println(e.getMessage());  
            } catch (NumberFormatException e) {  
                System.out.println("Um dos números informados estão acima da capacidade de processamento desta aplicação. Por favor, tente novamente com um número menor.");  
            }        
        }    
    }  
    public static void count(int num1, int num2) throws InvalidParametersException { /* lógica descrita acima */ }

A primeira coisa que fizemos foi, então, envolver todo o try-catch em um laço while, e definimos a condição como true. Ou seja, enquanto true for... verdadeiro, o laço se repetirá.
Fizemos um famigerado loop infinito, a perdição de todo processador.

Em vez de colocarmos a condição para parada do while na sua definição, apenas colocamos um break ao final da chamada ao método count(); desse modo, se não houver alguma exceção lançada, o loop será interrompido.

Ao final da chamada, definimos mais um bloco catch, capturando a exceção NumberFormatException e passando uma mensagem de erro mais fácil de ser compreendida. Bora testar pra ver se está tudo certo?
Desafio de Projeto - Criando uma aplicação contadora
Bom demais.

Agora, a única coisa que falta é chamar o método Counter.main() na classe Main. Pode ser redundante, mas eu prefiro deixar bem separadinhas e explicadas as coisas.

public class Main {  
    public static void main(String[] args) {  
        Counter.main(args);  
    }
}

Desafio de Projeto - Criando uma aplicação contadora

É isso aí, pessoal. Obrigado pela paciência e por ter lido esse post gigantesco.
O repositório desse projetinho pode ser encontrado aqui. Até a próxima!

以上是项目挑战 - 创建计数器应用程序的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?Mar 17, 2025 pm 05:46 PM

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?Mar 17, 2025 pm 05:44 PM

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?Mar 17, 2025 pm 05:43 PM

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Mar 17, 2025 pm 05:35 PM

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具