Aula Prática #02 - Input/Output e Mooshak


Exercício 1) Introdução à classe Scanner

Use a documentação da classe Scanner como referência quando precisar.

// Importa a classe Scanner, que será usada para leitura de dados
import java.util.Scanner;

public class Sum {
   public static void main(String[] args) {

      // Cria um objecto Scanner para ler da entrada padrão ("standard input")
      Scanner stdin = new Scanner(System.in);

      // Chama o método nextInt() para ir buscar o próximo inteiro
      int a = stdin.nextInt();
      int b = stdin.nextInt();

      // Imprime a soma dos dois números
      System.out.println(a+b);
   }

}

  1. O meu primeiro programa com Scanner.
    Copie este pedaço de código para um ficheiro, compile-o e execute o programa. A execução deverá ficar "parada" à espera que introduza dois números. Escreva 2 3, carregue no enter e verifique que o programa escreve 5 como resultado.
  2. Importação de classes.
    Experimente comentar a segunda linha do programa (a instrução import) e compile de novo o código. O que acontece?
    A classe Scanner faz parte do pacote java.util, que contém toda uma série de classes muito úteis que iremos aos poucos começar a usar.
  3. Espaçamento.
    Experimente executar o programa novamente, mas desta vez escrever 2, carregar no enter, depois escrever 3 e carregar novamente no enter, verificando que o programa continue a funcionar. Isto acontece porque o método nexInt() aceita qualquer tipo de espaçamento entre inteiros (sejam apenas um ou vários espaços, tabs e mudanças de linha).
  4. Erro no tipo de dados. (Input Mismatch)
    Execute novamente o programa mas desta vez dê como input 2.5 3.6. O que acontece? Porquê?
  5. Lendo outro tipo de dados.
    Modifique o programa para que passe a conseguir ler número com casas decimais ao invés de inteiros. Queremos usar doubles em vez de ints. Que método deverá ser chamado no lugar do nextInt()? (espreite novamente a documentação da classe Scanner. Teste o seu programa para garantir que com 2.5 3.6 como entrada o resultado é 6.1.
    (Nota: se usar um computador configurado para português, pode acontecer que ao tentar ler um número decimal com um ponto receba um "Input Mismatch"; nesse caso é esperado que use uma vírgula no lugar do ponto; não há problema pois quando submeter o seu programa ele irá aceitar na mesma pontos - em todo o caso, se desejar usar pontos também no seu computador pode modificar o Locale de todo o programa ou apenas no Scanner)

Exercício 2) Leitura de strings

import java.util.Scanner;

public class Count {
   public static void main(String[] args) {
	
      Scanner stdin = new Scanner(System.in);
		
      // Ciclo para iterar sobre todas as linhas do input
      int counter = 0;
      while (stdin.hasNextLine()) {
         counter++;
         String s = stdin.nextLine();
         System.out.println(counter + ": " + s);
      }
   }
}

  1. Executar o programa com o input num ficheiro
    Faça download do ficheiro hamlet.txt contendo alguns versos de Hamlet, uma peça de William Shakespeare. Compile o código de cima e execute-o fornecendo como input o ficheiro hamlet.txt usando redirecionamento de input na shell:
     
    $ java Count < hamlet.txt
    1: To be or not to be that is the question
    2: Whether tis nobler in the mind to suffer
    3: The slings and arrows of outrageous fortune
    4: Or to take arms against a sea of troubles

     
    Note que redirecionar o input (a parte "< hamlet.txt" na instrução acima) é "equivalente" a introduzir manualmente o conteúdo do ficheiro via teclado. Esta técnica poderá ser útil para facilitar o teste de inputs muito grandes ou de vários casos de input.
  2. Lendo tokens
    Altere o programa, substituindo a chamada a hasNextLine() por hasNext(), e a chamada a nextLine() por next(). Recompile e execute novamente o código com o mesmo input. O que acontece agora? O que está a ser contado?
    Em Java não existe nenhum "nextString" e o método next deve ser usado para ler pedaços de input (tokens) separados por algum tipo de espaçamento (sejam espaços ou mudanças de linha)

Exercício 3) Utilização de arrays

import java.util.Scanner;

public class ReadNumbers {

   // Escrever os numeros guardados num array no stdout
   static void writeArray(int v[]) {
      for (int i=0; i<v.length; i++)          
         System.out.println("v[" + i + "] = " + v[i]);      
   }
   
   public static void main(String[] args) {

      Scanner stdin = new Scanner(System.in);

      int v[] = new int[10];     // Cria um novo array com espaço para 10 inteiros           
      int n = stdin.nextInt();   // Ler a quantidade de numeros que se seguem
      
      for (int i=0; i<n; i++)    // Ler os numeros a partir do stdin
         v[i] = stdin.nextInt();
      
      writeArray(v);             // Chamar procedimento que escreve
   }
}
  1. Executar o código.
    Compile e execute este código, redirecionando o input a partir do ficheiro numbers.txt
    $ java ReadNumbers < numbers.txt
  2. Posições do array por preencher.
    Substitua o 10 no início do input por um 5 e execute novamente o programa. O que acontece? Porquê? Note como o atributo length de um array indica o tamanho que foi alocado, e não o número de posições "preenchidas". Note também qual o valor por omissão de um inteiro.
  3. Saindo fora dos limites do array. (ArrayIndexOutOfBoundsException)
    Mude o ficheiro de input para passar a conter 11 números (mude a primeira linha para 11 e acrescente um número no final da segunda linha) e execute novamente o programa. O que acontece? Porquê? Note que ao contrário do C, o Java indica explicitamente quando saimos fora dos limites de um array.
    Modifique o programa para passar a aceitar uma qualquer quantidade de números inteiros (a que for indicada na primeira linha de input) e teste a sua alteração.
  4. Calculando a amplitude.
    Acrescente uma função que recebe um array e devolve um inteiro indicando a amplitude (diferença entre máximo e mínimo) dos valores guardados no array. Teste o seu funcionamento e certifique-se que funciona independentemente da magnitude dos números (podem ser tão pequenos - incluindo números negativos - ou grandes como quiserem, assumindo que cabem num int).

Exercício 4) Resolução do Problemas - [ED183] Estatísticas


  1. Resolva o problema [ED183] Estatísticas e poderá usar Mooshak para ajudar a testar a sua solução (ver ajuda do Mooshak).
    Note que:
    • Este problema é uma continuação do exercício anterior (falta acrescentar uma nova função para calcular a média)
    • Para imprimir um double com duas casas decimais pode usar a instrução printf (como no C). Por exemplo, imprimir uma variável x com duas casas decimais seria System.out.printf("%.2f\n", x);
    • Note que não tem de verificar se o input obedece aos limites dados no enunciado. Pelo contrário, essas restrições estão lá para lhe garantir que os dados respeitam esses limites (ex: assim sabe que nunca irão existir mais que 1000 números inteiros nos inputs que são dados ao seu programa no Mooshak).
    • Todas as linhas do input e do output devem terminar com o caracter de mudança de linha (mesmo a última)

Exercício 5) Resolução dos Problemas - [ED120] Desenhando um Losango e [ED121] Palíndromos

  1. Resolva o problema [ED120] Desenhando um Losango e poderá usar Mooshak para ajudar a testar a sua solução.
    Algumas dicas:
    • Este problema é essencialmente igual a algo sugerido na aula anterior;
    • Para o resolver apenas necessita de saber como usar ciclos. Quantos pontos existem na primeira linha? E na segunda? E na terceira? E cardinais?
  2. Resolva o problema [ED121] Palíndromos e poderá usar Mooshak para ajudar a testar a sua solução.
    Algumas dicas:
    • Para a leitura do input pode usar o que aprendeu exercício 2 desta aula;
    • Se quiser aceder ao i-ésimo caracter de uma String pode usar o método char charAt(int i), como viu na aula anterior.
    • Primeiro converta a a linha lida numa string só com letras minúsculas (sem espaços e pontuações). Faça para isso uma função que receba uma string e devolva a mesma string com os espaços retirados e todas as maiúsculas convertidas em minúsculas. Para isso é útil conhecer a classe Character, que contém várias funções para lidar com caracteres. Em particular:
      • A função boolean Character.isLetter(char c) indica se o caracter c é uma letra;
      • A função char Character.toLowerCase(char c) converte o caracter para a sua versão minúscula
    • Faça agora uma outra função que recebe uma string e devolve um valor booleano indicando se a string é ou não um palíndromo, sendo que pode aplicar esta função à linha já sem espaços e maiúsculas.

Resolução de Exercícios Adicionais

Estes exercícios são um pouco mais avançados, mas permitem que exercite conhecimentos de leitura/escrita, uso de instruções condicionais e uso de instruções de ciclo. As dicas estão acessíveis se carregar no botão, mas estão "escondidas" para o caso de preferir primeiro tentar fazer sem spoilers.

  1. Resolva o problema [ED243] Pizza e também poderá testar a sua solução no Mooshak


  2. Resolva o problema [ED244] Primos e também poderá testar a sua solução no Mooshak.