terça-feira, 2 de dezembro de 2014

Força Senha

Componente para medir a força da senha

Este post irá exibir como implementar um medidor de força de senha utilizando o padrão de projeto Template Method, tendo como regra para o cálculo o valor do desvio padrão entre os caracteres de acordo com a tabela ASCII.

Bom, para começar vamos desenvolver uma classe abstrata Senha, que será nossa super classe

/**
 * Classe abstrata para medir a forca da senha
 */
public abstract class Senha {
 
 private Forca forcaSenha;
 private Pattern patter = this.getPatter();
 private Matcher matcher;
 private int frequencia;
 private int tamanhoInicial;
 private int tamanhoFinal;
 private Double desvioPadrao;

 public int getTamanhoInicial() {
  return tamanhoInicial;
 }

 public void setTamanhoInicial(int tamanhoInicial) {
  this.tamanhoInicial = tamanhoInicial;
 }

 public int getTamanhoFinal() {
  return tamanhoFinal;
 }

 public void setTamanhoFinal(int tamanhoFinal) {
  this.tamanhoFinal = tamanhoFinal;
 }
        
        
      /**
       * Metodo para testar a forca da senha digitada
       * 
       * @param senha - recebe uma string senha
       * @return forcaSenha - retorna uma constante do objeto Forca
       * @throws tamanho - lanca uma excecao se o tamanho da senha for menor que o valor minimo
       * ou maior que o valor maxio
       * @throws caracter - lanca uma excecao se algum caracter digitado for diferente da regra
       */
 protected Forca testaSenha(String senha) {

  matcher = patter.matcher(senha);
                
                frequencia = 0;
  while (matcher.find()) {

   frequencia++;

  }

  if (senha.length() > tamanhoFinal || senha.length() < tamanhoInicial) {
   
   throw new RuntimeException(this.getExceptionTamanho(tamanhoInicial, tamanhoFinal));

  } else if (senha.length() != frequencia) {

   throw new RuntimeException (this.getExceptionNome() + this.getNome());

  } else {

   desvioPadrao = this.getDesvioPadrao(frequencia, senha);
  }

  if (desvioPadrao <= this.getDesvioPadraoMuitoFraco()) {
   forcaSenha = Forca.MuitoFraca;
  } else if (desvioPadrao > this.getDesvioPadraoMuitoFraco()
    && desvioPadrao <= this.getDesvioPadraoFraco()) {
   forcaSenha = Forca.Fraca;
  } else if (desvioPadrao > this.getDesvioPadraoFraco()
    && desvioPadrao <= this.getDesvioPadraoMedio()) {
   forcaSenha = Forca.Media;
  } else if (desvioPadrao > this.getDesvioPadraoMedio()
    && desvioPadrao <= this.getDesvioPadraoForte()) {
   forcaSenha = Forca.Forte;
  } else if (desvioPadrao > this.getDesvioPadraoForte()) {
   forcaSenha = Forca.MuitoForte;
  }

  return forcaSenha;
 }

Agora temos que importar o Matcher e o Pattern do java.util, que são expressões regulares utilizadas para procurar em uma string os caracteres de um determinado intervalo. Também vamos criar os métodos abstratos, os quais serão responsáveis por obter as informações do objeto que está em questão e a classe enum Forca, para obter as constantes de força da senha.


import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Classe abstrata para medir a forca da senha
 */
public abstract class Senha {
 

       /**
        * Classe enum Forca com as constantes de forca da senha
        */
 public enum Forca {MuitoFraca, Fraca, Media, Forte,MuitoForte }
 

 
 private Forca forcaSenha;
 private Pattern patter = this.getPatter();
 private Matcher matcher;
 private int frequencia;
 private int tamanhoInicial;
 private int tamanhoFinal;
 private Double desvioPadrao;

 public int getTamanhoInicial() {
  return tamanhoInicial;
 }

 public void setTamanhoInicial(int tamanhoInicial) {
  this.tamanhoInicial = tamanhoInicial;
 }

 public int getTamanhoFinal() {
  return tamanhoFinal;
 }

 public void setTamanhoFinal(int tamanhoFinal) {
  this.tamanhoFinal = tamanhoFinal;
 }
        
        
      /**
       * Metodo para testar a forca da senha digitada
       * 
       * @param senha - recebe uma string senha
       * @return forcaSenha - retorna uma constante do objeto Forca
       * @throws tamanho - lanca uma excecao se o tamanho da senha for menor que o valor minimo
       * ou maior que o valor maxio
       * @throws caracter - lanca uma excecao se algum caracter digitado for diferente da regra
       */
 protected Forca testaSenha(String senha) {

  matcher = patter.matcher(senha);
                
                frequencia = 0;
  while (matcher.find()) {

   frequencia++;

  }

  if (senha.length() > tamanhoFinal || senha.length() < tamanhoInicial) {
   
   throw new RuntimeException(this.getExceptionTamanho(tamanhoInicial, tamanhoFinal));

  } else if (senha.length() != frequencia) {

   throw new RuntimeException (this.getExceptionNome() + this.getNome());

  } else {

   desvioPadrao = this.getDesvioPadrao(frequencia, senha);
  }

  if (desvioPadrao <= this.getDesvioPadraoMuitoFraco()) {
   forcaSenha = Forca.MuitoFraca;
  } else if (desvioPadrao > this.getDesvioPadraoMuitoFraco()
    && desvioPadrao <= this.getDesvioPadraoFraco()) {
   forcaSenha = Forca.Fraca;
  } else if (desvioPadrao > this.getDesvioPadraoFraco()
    && desvioPadrao <= this.getDesvioPadraoMedio()) {
   forcaSenha = Forca.Media;
  } else if (desvioPadrao > this.getDesvioPadraoMedio()
    && desvioPadrao <= this.getDesvioPadraoForte()) {
   forcaSenha = Forca.Forte;
  } else if (desvioPadrao > this.getDesvioPadraoForte()) {
   forcaSenha = Forca.MuitoForte;
  }

  return forcaSenha;
 }
        

       /**
        * Metodo abstrato para obter a string, da subclasse, a ser lancada no exception
        * para quando o usuario digita um caracter diferente do definido pela subclasse
        * 
        * @return retorna uma string com a exception
        */

 protected abstract String getExceptionNome();

      /**
        * Metodo abstrato para obter a string, da subclasse, a ser lancada no exception
        * para quando a senha digitada excede o tamanho definido como maximo e minimo
        * 
        * @param tamanhoInicialException - inteiro com o tamanho minimo de caracteres que a 
        * senha deve conter
        * @param tamanhoFinalException - inteiro com o tamanho maximo de caracteres que a senha
        * deve conter
        * @return retorna uma string com a exception
        */

 protected abstract String getExceptionTamanho(int tamanhoInicialException, int tamanhoFinalException);
 
        
      /**
        * Metodo abstrato para obter o calculo do desvio padrao, da subclasse, para verificar 
        * a forca da senha de acordo com os valores definidos pelo programador
        * 
        * @param frequenciDesvioPadrao - inteiro com a quantidade de caracteres digitados
        * na senha
        * @param senha - string com a senha digitada pelo usuario
        * @return retorna um valor double com o calculo do desvio padrao
        */
 protected abstract double getDesvioPadrao(int frequenciaDesvioPadrao, String senha);

        
      /**
        * Metodo abstrato para obter a string, da subclasse, a ser lancada no exception
        * contendo o nome dos caracteres que devem obrigatoriamento compor a senha
        * 
        * @return retorna uma string com o nome dos caracteres
        */
 protected abstract String getNome();
        
        
      /**
        * Metodo abstrato para obter o Pattern, da subclasse, com o intervalo de caracteres
        * que devem compor a senha
        * 
        * @return retorna o pattern com o intervalo de caracteres
        */
 protected abstract Pattern getPatter();
        
        
      /**
        * Metodo abstrato para obter, da subclasse, o valor definido pelo programador 
        * para quando a senha eh muito fraca
        * 
        * @return retorna um double com o valor definido como muito fraco
        */
 protected abstract double getDesvioPadraoMuitoFraco();
        
        
      /**
        * Metodo abstrato para obter, da subclasse, o valor definido pelo programador 
        * para quando a senha eh fraca
        * 
        * @return retorna um double com o valor definido como fraco
        */
 protected abstract double getDesvioPadraoFraco();
        
        
      /**
        * Metodo abstrato para obter, da subclasse, o valor definido pelo programador 
        * para quando a senha eh muito media
        * 
        * @return retorna um double com o valor definido como medio
        */
 protected abstract double getDesvioPadraoMedio();
        
        
      /**
        * Metodo abstrato para obter, da subclasse, o valor definido pelo programador 
        * para quando a senha eh forte
        * 
        * @return retorna um double com o valor definido como muito forte
        */
 protected abstract double getDesvioPadraoForte();
        
        
      /**
        * Metodo abstrato para setar, na subclasse, o valor definido pelo programador 
        * para quando a senha eh muito fraca
        * 
        * @param getDesvioPadraoMuitoFraco - double com o valor que o programador
        * ira definir para o desvio padrao muito fraco
        * @return retorna um double com o valor definido como muito fraco
        */
 protected abstract void setDesvioPadraoMuitoFraco(double getDesvioPadraoMuitoFraco);
        
        
      /**
        * Metodo abstrato para setar, na subclasse, o valor definido pelo programador 
        * para quando a senha eh fraca
        * 
        * @param getDesvioPadraoFraco - double com o valor que o programador
        * ira definir para o desvio padrao fraco
        * @return retorna um double com o valor definido como fraco
        */
 protected abstract void setDesvioPadraoFraco(double getDesvioPadraoFraco);
        
        
      /**
        * Metodo abstrato para setar, na subclasse, o valor definido pelo programador 
        * para quando a senha eh media
        * 
        * @param getDesvioPadraoMedio - double com o valor que o programador
        * ira definir para o desvio padrao medio
        * @return retorna um double com o valor definido como medio
        */
 protected abstract void setDesvioPadraoMedio(double getDesvioPadraoMedio);
        
        
      /**
        * Metodo abstrato para setar, na subclasse, o valor definido pelo programador 
        * para quando a senha eh forte
        * 
        * @param getDesvioPadraoForte - double com o valor que o programador
        * ira definir para o desvio padrao forte
        * @return retorna um double com o valor definido como forte
        */
 protected abstract void setDesvioPadraoForte(double getDesvioPadraoForte);
 

}

Com a nossa super classe criada, agora vamos criar duas subclasses, a senhaCaracteres que será para senha com apenas caracteres (maiúsculo e minúsculo) e a senhaNumeros que será para senha com apenas números.


package componente;

import java.util.regex.Pattern;

public class SenhaCaracter extends Senha {

 private double desvioPadrao;
 private double desvioPadraoForte;
 private double desvioPadraoMedio;
 private double desvioPadraoFraco;
 private double desvioPadraoMuitoFraco;

 @Override
 protected Pattern getPatter() {
  return Pattern.compile(".??[a-zA-Z]");
 }

 @Override
 protected String getNome() {
  return "caracteres minusculos e maiusculos";
 }

 @Override
 protected double getDesvioPadrao(int frequencia, String senha) {

  Estatistica estatistica = new Estatistica();
  
  char[] chars = senha.toCharArray();
  
  estatistica.setArray(chars);  
  desvioPadrao = estatistica.getDesvioPadrao();
  System.out.println(desvioPadrao);
  
  senha = new String(chars);
  
  return desvioPadrao;
 }

 @Override
 protected double getDesvioPadraoMuitoFraco() {
  return desvioPadraoMuitoFraco;
 }

 protected void setDesvioPadraoMuitoFraco(double desvioPadraoMuitoFraco) {
  this.desvioPadraoMuitoFraco = desvioPadraoMuitoFraco;
 }

 @Override
 protected double getDesvioPadraoFraco() {
  return desvioPadraoFraco;
 }

 protected void setDesvioPadraoFraco(double desvioPadraoFraco) {
  this.desvioPadraoFraco = desvioPadraoFraco;
 }

 @Override
 protected double getDesvioPadraoMedio() {
  return desvioPadraoMedio;
 }

 protected void setDesvioPadraoMedio(double desvioPadraoMedio) {
  this.desvioPadraoMedio = desvioPadraoMedio; 
 }

 @Override
 protected double getDesvioPadraoForte() {
  return desvioPadraoForte;
 }

 protected void setDesvioPadraoForte(double desvioPadraoForte) {
  this.desvioPadraoForte = desvioPadraoForte;  
 }

 @Override
 protected String getExceptionNome() {
  return ("A senha deve conter apenas caracteres: ");
 }

 @Override
 protected String getExceptionTamanho(int tamanhoInicial, int tamanhoFinal) {
  return ("A senha deve conter no minimo " + tamanhoInicial
    + " e no maximo " + tamanhoFinal + " caracteres!");
 }
 

 

 
}


package componente;

import java.util.regex.Pattern;


public class SenhaNumeros extends Senha{

 private double desvioPadrao;
 private double desvioPadraoForte;
 private double desvioPadraoMedio;
 private double desvioPadraoFraco;
 private double desvioPadraoMuitoFraco;

 @Override
 protected Pattern getPatter() {
  return Pattern.compile(".??[0-9]");
 }

 @Override
 protected String getNome() {
  return "numeros";
 }

 @Override
 protected double getDesvioPadrao(int frequencia, String senha) {
  
  Estatistica estatistica = new Estatistica();
  
  char[] chars = senha.toCharArray();
  
  estatistica.setArray(chars);  
  desvioPadrao = estatistica.getDesvioPadrao();
  System.out.println(desvioPadrao);
  
  senha = new String(chars);
  
  return desvioPadrao;
 }

 @Override
 protected double getDesvioPadraoMuitoFraco() {
  return desvioPadraoMuitoFraco;
 }

 protected void setDesvioPadraoMuitoFraco(double desvioPadraoMuitoFraco) {
  this.desvioPadraoMuitoFraco = desvioPadraoMuitoFraco;
  
 }

 @Override
 protected double getDesvioPadraoFraco() {
  return desvioPadraoFraco;
 }

 protected void setDesvioPadraoFraco(double desvioPadraoFraco) {
  this.desvioPadraoFraco = desvioPadraoFraco;
 }

 @Override
 protected double getDesvioPadraoMedio() {
  return desvioPadraoMedio;
 }

 protected void setDesvioPadraoMedio(double desvioPadraoMedio) {
  this.desvioPadraoMedio = desvioPadraoMedio; 
 }

 @Override
 protected double getDesvioPadraoForte() {
  return desvioPadraoForte;
 }

 protected void setDesvioPadraoForte(double desvioPadraoForte) {
  this.desvioPadraoForte = desvioPadraoForte;  
 }

 @Override
 protected String getExceptionNome() {
  return ("A senha deve conter apenas caracteres: ");
 }

 @Override
 protected String getExceptionTamanho(int tamanhoInicial, int tamanhoFinal) {
  return ("A senha deve conter no minimo " + tamanhoInicial
    + " e no maximo " + tamanhoFinal + " caracteres!");
 }

 
}


Por último, criaremos a nossa classe Estatistica que terá os métodos para calcular o desvio padrão e a classe Exception.


package componente;

import java.util.Arrays;

public class Estatistica {

 private char array[];

 public double getPearson() {

  return (getDesvioPadrao() / getMediaAritmetica()) * 100;

 }

 public double getMediaAritmetica() {

  double total = 0;

  for (int counter = 0; counter < array.length; counter++)

   total += array[counter];

  return total / array.length;

 }

 public double getSomaDosElementos() {

  double total = 0;

  for (int counter = 0; counter < array.length; counter++)

   total += array[counter];

  return total;

 }

 public double getSomaDosElementosAoQuadrado() {

  double total = 0;

  for (int counter = 0; counter < array.length; counter++)

   total += Math.pow(array[counter], 2);

  return total;

 }

 public double getMediaAritmetica(double array[]) {

  double total = 0;

  for (int counter = 0; counter < array.length; counter++)

   total += array[counter];

  return total / array.length;

 }

 public double getSomaDosElementos(double array[]) {

  double total = 0;

  for (int counter = 0; counter < array.length; counter++)

   total += array[counter];

  return total;

 }

 public void ordenar() {

  Arrays.sort(array);

 }

 public void imprimeArray() {

  System.out.print("\nElementos do Array: ");

  for (int count = 0; count < array.length; count++)

   System.out.print(array[count] + " ");

 }

 public double getVariancia() {

  double p1 = 1 / Double.valueOf(array.length - 1);

  double p2 = getSomaDosElementosAoQuadrado()

  - (Math.pow(getSomaDosElementos(), 2) / Double

  .valueOf(array.length));

  return p1 * p2;

 }

 public double getDesvioPadrao() {

  return Math.sqrt(getVariancia());

 }

 public double getMediana() {

  this.ordenar();

  int tipo = array.length % 2;

  if (tipo == 1) {

   return array[((array.length + 1) / 2) - 1];

  } else {

   int m = array.length / 2;

   return (array[m - 1] + array[m]) / 2;

  }

 }

 public void setArray(char[] array) {

  this.array = array;

 }

}


/**
  * Classe Exception extendendo a classe RuntimeException
*/
public class Exception extends RuntimeException {

 private static final long serialVersionUID = 1L;

 public Exception(String mensagem, Exception e) {
  super(mensagem, e);
 }

 public Exception(String mensagem) {
  super(mensagem);
 }
}

Pronto!! Agora só testar, instanciando e setando o tamanho inicial e final que a senha deve conter e o desvio padrão para a regra do medidor.


package Negocio;

public class Main {


 public static void main(String[] args) {
  
  
  
  String senha = "cA"; 
  
/*  
  
  Senha todos = new SenhaTodosCaracteres();
  Senha numeros = new SenhaNumeros();
  Senha minusculo = new SenhaCaracterMinusculo();
  Senha maiusculo = new SenhaCaracterMaiusculo();
  Senha caracter = new SenhaCaracter();
  Senha caracterEspecial = new SenhaCaracterEspecial();
  
  todos.setTamanhoInicial(2);
  todos.setTamanhoFinal(5);
  
  numeros.setTamanhoInicial(2);
  numeros.setTamanhoFinal(10);
  
  minusculo.setTamanhoInicial(10);
  minusculo.setTamanhoFinal(20);
  
  maiusculo.setTamanhoInicial(20);
  maiusculo.setTamanhoFinal(20);
  
  caracter.setTamanhoInicial(5);
  caracter.setTamanhoFinal(15);
  
  caracterEspecial.setTamanhoInicial(5);
  caracterEspecial.setTamanhoFinal(15);
  
  numeros.setDesvioPadraoMuitoFraco(1);
  numeros.setDesvioPadraoFraco(3);
  numeros.setDesvioPadraoMedio(5);
  numeros.setDesvioPadraoForte(8);
  
    
  System.out.println(numeros.testaSenha(senha));
  System.out.println(minusculo.testaSenha(senha));
  System.out.println(maiusculo.testaSenha(senha));
  System.out.println(caracter.testaSenha(senha));
  System.out.println(caracterEspecial.testaSenha(senha));
    
  
*/ 
  Senha numeros = new SenhaCaracter();
  
  
  numeros.setTamanhoInicial(2);
  numeros.setTamanhoFinal(10);
  numeros.setDesvioPadraoMuitoFraco(1);
  numeros.setDesvioPadraoFraco(3);
  numeros.setDesvioPadraoMedio(5);
  numeros.setDesvioPadraoForte(8);
  
  
  System.out.println(numeros.testaSenha(senha));
 }

}


quinta-feira, 2 de outubro de 2014

Obtenção de Requisitos

A primeira etapa para escrever um software é a garantir que ele faça o que foi pedido, o que não é uma tarefa fácil. Como garantir que o cliente está ciente de tudo que ele precisa? Como saber se o programador entendeu tudo aquilo que o cliente solicitou? Para isso existem os bons requisitos, que garantem que aquilo que será entregue aquilo que foi pedido.
A primeira coisa a fazer é entender aquilo que o cliente quer e a melhor maneira disso acontecer é deixá-lo falar e prestar atenção no que o sistema precisa fazer.
A segunda é criar uma lista de requisitos, ou seja, transformar as palavras do cliente em um conjunto básico de requisitos.

Lista de requisitos: 
Além da lista de requisitos, é necessário entender como o software será utilizado, pois nem sempre o cliente saberá o que ele quer. Portanto fazer perguntas para o cliente é fundamental para que o produto seja entregue fazendo o que foi solicitado.

Planejar o erro:
Nem sempre o usuário vai utilizar o programa da maneira como ele foi planejado para ser usado, portanto é importante tentar prever os erros que podem acontecer e acrescentar soluções para eles.

Casos de uso:
Uma boa ajuda na hora de obter os requisitos é escrever uma lista de tarefas que o sistema tem que cumprir, assim fica mais fácil visualizar as falhas que o sistema pode ter e adiantar as soluções. Um caso de uso é uma descrição do que o sistema deve fazer para atingir seu objetivo, cada caso de uso oferece mais de uma situação que conduz como o sistema deve interagir. Um bom caso de uso é dividido em três partes:
  1. Valor evidente: Todo caso de uso deve ter uma valor evidente para o sistema, se ele não atingir o objetivo não será útil.
  2. Início e fim: Todo caso de uso deve ter algo que o inicie e o termine.
  3. Iniciador externo: Casos de uso são disparados por iniciadores externos, ou seja, qualquer coisa fora do sistema.
Verificar os requisistos para os casos de uso:
Após obter um conjunto ininical de requisitos e casos de uso, é bom verificar se todos os requisistos abordam tudo que o sistema deve fazer.

Código e teste:
Após o levantamento dos casos de uso, dos requisistos é hora de programar, testar o código e entregar para o cliente pra que ele avalie aquilo que foi feito.

Referência:
MCLAUGHLIN, B; POLLICE, G.; WEST, D. Use a cabeça! Análise e Projeto Orientado a Objeto. Alta books, 2007.

quinta-feira, 25 de setembro de 2014

Refatoração de Software

Refatoração de Software

Refatoração nada mais é do que alterar um sistema de software de modo que essa alteração não comprometa o comportamento externo do código, sendo assim é uma maneira disciplinada de aperfeiçoar o código onde as chances de falhas são minimizadas. Então, quando você refatora um código você está melhorando o projeto deste após o mesmo ter sido escrito. O propósito da refatoração é tornar o software legível a ponto que qualquer pessoa entende-lo, apenas estas mudanças são consideradas refatorações.

Kent Beck utiliza uma metáfora, denominada de os dois chapéus, onde diz que quando você desenvolve um sistema você utiliza basicamente duas atividades distintas: adicionar funções e refatorá-las. Neste desenvolvimento você geralmente se descobre trocando de chapéu, onde você começa adicionando uma nova função e após troca de chapéu e refatora esta funcionalidade.

Porque você deve refatorar?

- Melhora o projeto do software: Um sistema não refatorado normalmente necessita de mais códigos para as mesmas funções, sendo esses replicados diversas vezes.

-Torna o software legível: Ao desenvolver um sistema geralmente após um tempo outros programadores fazem alterações nesse código, então faz muita diferença o programador usar uma semana para entender o código e fazer a modificação ao invés de utilizar horas se o código fosse legível.

-Ajuda a encontrar falhas: Ao refatorar um código, você clareia certas suposições que havia feito até chegar ao ponto de não conseguir evitar de encontrar falhas.

-Ajuda a desenvolver mais rápido: Sem um bom projeto você progride rapidamente durante um certo tempo, porém ao longo de um projeto mau estruturado, você acaba perdendo mais tempo procurando e consertando falhas do que adicionando novas funcionalidades.

Quando você deve refatorar?

-Acrescentando novas funções: Um motivo que conduz a refatoração é quando você tem dificuldade em adicionar novas funcionalidades. Quando você precisa pensar muito tempo para saber o que o código faz é hora de refatorá-lo.

-Precisa consertar falhas: Quando você é notificado de uma falha é o sinal de que o código precisa ser refatorado, já que esse não estava claro o suficiente para detectar a falha.

-Enquanto revisa o código: As revisões de código regulares facilitam o entendimento de outros desenvolvedores em aspectos de um sistema grande e também a transmissão do conhecimento dos mais para os menos experientes.

Porque a refatoração funciona?

Programas que são difíceis de ler, que tem lógica duplicada, que para incluir novas funcionalidades requer modificação no código existente e com lógicas condicionais complexas, são difíceis de modificar.

Quando você não deve refatorar?

Há vezes em que o código está tão confuso que você até poderia refatorá-lo, porém é mais fácil reescrevê-lo. Outras vezes você se encontra muito perto do prazo final da entrega do software, então acaba adiando a refatoração.

Exemplo de refatoração:

Código não refatorado.:

public class StringUtil{
 private StringUtil(){}
 public static String us(String a){
  if(a==null){
   throw new NullPointerException("O campo não pode ser nulo");
  }
  char[] c = a.toCharArray();
  for (int i=0; i < a.length; i++){
   if((a[i] >= 97 && a[i] <= 122) || a[i]==231){
     a[i] -= 32;
   }
  }
 }
}

Código refatorado.:


public class StringUtil{


  private static final String EXCEPTION_MESSAGE = "O campo não pode ser nulo";
  private static final int DIF_MIN_MAIUS = 32;

  private StringUtil(){}

 /**
  * Converte uma String Minuscula para Maiuscula
  *
  *
  * @param str - A String em minusculo
  * @return Retorna uma nova String em maiusculo
  * @throw Lanca uma excecao quando o campo eh nulo
 */

 public static String upperString(String str){

  if(str == null) throw new NullPointerException(EXCEPTION_MESSAGE);

  char[] chars = str.toCharArray();

  for(int i = 0;i < chars.length;i++) chars[i] = if((chars[i] >= 97 && chars[i] <= 122) || chars[i]==231) chars[i] -= DIF_MIN_MAIUS;   

  return new String(chars);
}

Você pode notar que agora o código contém as seguintes alterações:

- O código está comentado, o que possibilita saber qual a função do método.

- O código possui duas variáveis contantes (EXCEPTION_MESSAGE,DIF_MIN_MAIUS) para não utilizar números ou símbolos mágicos.

- O código se torna legível, pois ao colocar o nome do método de 'upperString' ao invés de 'us', o nome da variável passada como parâmetro 'str' ao invés de 'a' e a variável do array 'chars' ao invés d 'c' possibilitam saber direto o que o método faz.

- O código evita '{}' desnecessárias.

Referência: Refatoração, de Martin Fowler.