O Java tem uma declaração de uso?


107

O Java tem uma instrução de uso que pode ser usada ao abrir uma sessão em hibernação?

Em C #, é algo como:

using (var session = new Session())
{


}

Portanto, o objeto sai do escopo e fecha automaticamente.


4
"permitindo definir um escopo para um objeto" Isso não é o que usingfaz. Escopo não é vitalício (e usingtambém não é vitalício, estritamente falando, já Disposeque não destrói a memória de um objeto.)
Joren

4
@Joren Seu comentário está sendo votado, mas eu gostaria de mais informações. Você é quem está introduzindo a ideia de "vida inteira" e então diz que não se trata de "vida inteira". Escopo é o termo usado na definição da biblioteca msdn, talvez eu o tenha usado incorretamente. Como você definiria o using statement.
Jla

1
O escopo se refere à área no código na qual você pode se referir a um identificador sem usar seu nome totalmente qualificado (variável local, tipo, nome do método e outros). A vida útil se refere ao tempo em que um objeto ou variável está acessível. Consulte blogs.msdn.com/b/ericlippert/archive/2009/08/03/…
Joren

2
Portanto, por exemplo, se você tiver uma variável local e atribuir uma instância do tipo de valor a ela, o tempo de vida de seu valor terminará quando o tempo de vida de sua variável terminar. Mas se você alocou um objeto e armazenou uma referência a ele em um local, então o tempo de vida desse objeto pode muito bem se estender além do tempo de vida de seu armazenamento, contanto que ainda haja alguma referência ao objeto em outro lugar. Quanto a using, ele automaticamente dispõe o objeto no final de seu escopo, mas não desaloca o objeto - seu tempo de vida não termina até que todas as suas referências tenham desaparecido.
Joren

Respostas:


124

Java 7 introduziu o Automatic Resource Block Management, que traz esse recurso para a plataforma Java. As versões anteriores do Java não tinham nada semelhanteusing .

Como exemplo, você pode usar qualquer variável implementada java.lang.AutoCloseableda seguinte maneira:

try(ClassImplementingAutoCloseable obj = new ClassImplementingAutoCloseable())
{
    ...
}

A java.io.Closeableinterface do Java , implementada por streams, se estende automaticamente AutoCloseable, de forma que você já pode usar streams em um trybloco da mesma forma que usaria em um usingbloco C # . Isso é equivalente a C # using.

A partir da versão 5.0, o Hibernate Sessions implementaAutoCloseable e pode ser fechado automaticamente em blocos ARM. Nas versões anteriores do Hibernate Session não implementouAutoCloseable . Portanto, você precisa estar em Hibernate> = 5.0 para usar este recurso.


1
"Felizmente", com o Java 7 disponível agora, essa resposta não é mais verdadeira (e acho que os blocos ARM são exatamente o que usingfazem).
Joachim Sauer

@Joachim Sauer: Obrigado. Atualizei minha resposta para refletir a passagem do tempo. Para o seu ponto de blocos ARM sendo exatamente o que o uso faz; no momento em que escrevi esta resposta, parecia-me que os blocos ARM deviam ser blocos try, enquanto o uso pode ser aplicado a qualquer bloco arbitrário. Olhando para ele agora, parece que a palavra-chave do pode ser usada em java para fazer isso. Isso foi adicionado à proposta recentemente ou eu perdi da primeira vez? Além disso, o OP perguntou especificamente sobre as Sessões de Hibernate. AFAIK: As sessões de hibernação ainda não implementam, AutoCloseableentão ainda não podem usar o ARM.
Asaph

1
Não ocorre no 4.3 Hibernate NÃO implementa AutoCloseable. docs.jboss.org/hibernate/orm/4.3/javadocs/index.html?org/… Acho que cabe a cada um escrever seu próprio wrapper?
Andrei Rînea

1
A sessão não pode implementar AutoCloseable porque Session.close () retorna uma conexão. Eu acho que este é um projeto ruim, mas duvido que vá ser mudado.
usr-local-ΕΨΗΕΛΩΝ

@ usr-local-ΕΨΗΕΛΩΝ Eu apenas percebi que eles obrigariam qualquer um que esteja usando o hibernate a mudar para o java 7 se implementassem essa interface. AutoCloseablenão existia antes de java 7, não é?
Neil

31

Antes do Java 7 , não existia tal recurso no Java (para Java 7 e superior, veja a resposta de Asaph sobre ARM ).

Você precisava fazer isso manualmente e era uma dor :

AwesomeClass hooray = null;
try {
  hooray = new AwesomeClass();
  // Great code
} finally {
  if (hooray!=null) {
    hooray.close();
  }
}

E esse é apenas o código quando nem // Great codee nem hooray.close()pode lançar nenhuma exceção.

Se você realmente deseja limitar o escopo de uma variável, um bloco de código simples faz o trabalho:

{
  AwesomeClass hooray = new AwesomeClass();
  // Great code
}

Mas provavelmente não foi isso que você quis dizer.


1
Seu equivalente em Java não deve ser problema se // Great codelançar uma exceção.
Cheeso

3
Quando o construtor lança uma exceção, acho que seu código vai resultar em um NullPointerException que mascara a exceção original.
Michael Borgwardt

@Michael: na verdade, meu exemplo não compilava, porque horraypode não ter sido inicializado naquele ponto (corrigido agora).
Joachim Sauer

4
+1 para blocos simples flutuantes que podem limitar o escopo. No entanto, sempre que vejo isso, quase sempre é um indicador de que o método deve ser dividido em pedaços menores.
Mark Peters

1
se você quiser capturar qualquer exceção do construtor, você deve tê-la dentro do bloco try. seria complicado embrulhar tudo em outro try / catch.
ths



8

O equivalente java mais próximo é

AwesomeClass hooray = new AwesomeClass();
try{
    // Great code
} finally {
    hooray.dispose(); // or .close(), etc.
}



2

Se você estiver interessado em gerenciamento de recursos, o Projeto Lombok oferece a @Cleanupanotação. Retirado diretamente de seu site:

Você pode usar @Cleanuppara garantir que um determinado recurso seja limpo automaticamente antes que o caminho de execução do código saia do seu escopo atual. Você faz isso anotando qualquer declaração de variável local com a @Cleanup anotação assim:

@Cleanup InputStream in = new FileInputStream("some/file");

Como resultado, no final do escopo em que você está, in.close()é chamado. É garantido que essa chamada seja executada por meio de uma construção try / finally. Veja o exemplo abaixo para ver como isso funciona.

Se o tipo de objeto que você gostaria de limpar não tem um close() método, mas algum outro método sem argumento, você pode especificar o nome desse método assim:

@Cleanup("dispose") org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent, 0);

Por padrão, o método de limpeza é considerado close(). Um método de limpeza que leva argumento não pode ser chamado via @Cleanup.

Vanilla Java

import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    InputStream in = new FileInputStream(args[0]);
    try {
      OutputStream out = new FileOutputStream(args[1]);
      try {
        byte[] b = new byte[10000];
        while (true) {
          int r = in.read(b);
          if (r == -1) break;
          out.write(b, 0, r);
        }
      } finally {
        out.close();
      }
    } finally {
      in.close();
    }
  }
}

Com Lombok

import lombok.Cleanup;
import java.io.*;

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
  }
}


1

Consulte esta lista de palavras-chave Java .

  1. A usingpalavra-chave infelizmente não faz parte da lista.
  2. E também não há equivalência da usingpalavra-chave C # por meio de qualquer outra palavra-chave como agora em Java.

Para imitar tal "using"comportamento, você terá que usar um try...catch...finallybloco, onde você descartaria os recursos dentro dele finally.


6
O fato de usingnão ser uma palavra-chave não significa nada. O mesmo recurso pode ser (e será!) Implementado com outra palavra-chave, como @BalusC mencionou.
Joachim Sauer

1
Concordo! Mas, por enquanto, não existe, certo? Isso é o que o OP perguntou, se havia algo parecido agora. É bom saber que existirá em lançamentos futuros, mas isso não muda nada por agora, de uma forma ou de outra. De qualquer forma, as informações fornecidas por @BalusC são ótimas! =)
Will Marcouiller

2
Concordo com isso, mas seu post parece dizer que o fato de usingnão estar na lista de palavras-chave Java significa que esse recurso não está presente na linguagem Java. E isso não é verdade.
Joachim Sauer

Se é isso que minha postagem parece dizer, então irei editar para refletir minha intenção.
Will Marcouiller

Editei minha resposta especificando que não havia nenhuma usingpalavra-chave, e nem qualquer equivalência por enquanto. Obrigado @Joachim Sauer! =)
Will Marcouiller


0

Para responder à pergunta sobre limitar o escopo de uma variável, em vez de falar sobre o fechamento / descarte automático de variáveis.

Em Java, você pode definir escopos fechados e anônimos usando chaves. É extremamente simples.

{
   AwesomeClass hooray = new AwesomeClass()
   // Great code
}

A variável hoorayestá disponível apenas neste escopo, e não fora dele.

Isso pode ser útil se você tiver variáveis ​​repetidas que são apenas temporárias.

Por exemplo, cada um com índice. Assim como a itemvariável é fechada no loop for (ou seja, só está disponível dentro dela), a indexvariável é fechada no escopo anônimo.

// first loop
{
    Integer index = -1;
    for (Object item : things) {index += 1;
        // ... item, index
    }
}

// second loop
{
    Integer index = -1;
    for (Object item : stuff) {index += 1;
        // ... item, index
    }
}

Também uso isso às vezes se você não tiver um loop for para fornecer escopo de variável, mas quiser usar nomes de variáveis ​​genéricos.

{
    User user = new User();
    user.setId(0);
    user.setName("Andy Green");
    user.setEmail("andygreen@gmail.com");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("rachelblue@gmail.com");
    users.add(user);
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.