Pseudo-RAII em Java

Quando vejo um código nesse padrão:

InputStream is = getSomeInputStream();
try {
  // use 'is'
} catch(IOException ex) {
  // log ex
} finally {
  try {
    if (is != null) is.close();
  } catch(IOException ex) {}
}

Me dá náusea, vertigem, urticária! Comparem com este padrão:

try {
  final InputStream is = getSomeInputStream(); // se der exception vai lá pro catch
                                               // sem passar pelo finally
  try {
    // use 'is'                                // se der exception vai lá pro catch
                                               // passando pelo finally
  } finally {
    is.close();                                // certeza de que 'is' não é null
  }
} catch(IOException ex) {
  // log ex
}

Ele espelha a keyword ‘using’ do C#, só loga a exception uma vez e garante que ‘is’ é diferente de null no bloco ‘finally’ (e caso o close dispare uma exception, tem o catch logo abaixo).

Críticas?

Resto de divisão

Quando quero restringir um contador até um valor máximo, utilizo o operador ‘resto de divisão’. Digamos que eu tenha uma sequência de números (por exemplo, entre 0 e 29) e que eu precise somente dos valores entre 0 e 3:


Seq 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Seq % 4 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3

E quando isso é útil? Por exemplo, se você tiver um vetor com os caracteres “/-\|” e queira fazer uma ‘estrela de progresso’, pra indicar que está processando (em C):

void progresso(void) {
  static char* caracteres = "/-\\|";
  static size_t n_caracteres = strlen(caracteres);
  static int i = 0;
  printf("%c\b", caracteres[i]);
  i = (i+1) % n_caracteres;
}

Desta forma garantimos que o valor de “i” estará sempre entre zero e o tamanho do vetor de caracteres.

Dica de depuracao com breakpoint contadores

Ontem tive que depurar uma parte do codigo que nao era minha, mas que estava me bloqueando.

Era uma parte chata, numa classe-base de vaaarias classes. Era mais ou menos assim:

OnSomething(); // definido na classe derivada
ASSERT(SomethingElse(), “Esta classe precisa chamar __super::OnSomething()!”);

O problema era que quando o assert era disparado, ja era tarde demais! Eu estava na classe base e nao tinha como saber em qual instancia eu estava.

Pra resolver o problema, coloquei um breakpoint condicional com uma contagem de 100.000 (tanto faz o numero, desde que seja alto) na primeira linha e rodei. Assim que voou, anotei o numero (380). Mudei o contador pra 380 e rodei de novo.

Bingo! Parei antes de dar a craca! F11 (Step into) e pronto, descobri o metodo bugado!

Imagina se eu tivesse que contar na mao, a trabalheira que seria? 380 vezes?! Com certeza eu ia perder a conta!