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.

mrblah
fonte
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
1
possível duplicata da palavra-chave "usando" em java
HaveNoDisplayName

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.

Asaph
fonte
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.

Joachim Sauer
fonte
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

Tecnicamente:

DisposableObject d = null;
try {
    d = new DisposableObject(); 
}
finally {
    if (d != null) {
        d.Dispose();
    }
}
ChaosPandion
fonte
2
Não é a melhor maneira de fazer isso. stackoverflow.com/questions/1909662/…
Mark Byers
5
Isso seria essencialmente equivalente. Eu não me importo se é a melhor maneira.
ChaosPandion
2
Escrito como um verdadeiro programador C #. ;)
Neil
8

O equivalente java mais próximo é

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

Por enquanto, não.

Porém existe uma proposta de ARM para Java 7.

faltando faktor
fonte
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);
    }
  }
}
Adam Paynter
fonte
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.

Will Marcouiller
fonte
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
1

Os blocos ARM , da moeda do projeto , estarão em Java 7. Este recurso destina-se a trazer funcionalidade semelhante ao Java como o .Net usando sintaxe.

Krock
fonte
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("[email protected]");
    users.add(user);
}

{
    User user = new User();
    user.setId(1);
    user.setName("Rachel Blue");
    user.setEmail("[email protected]");
    users.add(user);
}
Alex
fonte