[lamer] автоматическое управление ресурсами в Java

Landstreicher

Недавно хотел переписать простенькую программу с C++ на Java — уперся в то, что не понимаю, как управлять ресурсами в Java.
В C++ для этих целей используется идиома RAII (resource allocation is initialization):
File f("myfile.txt");
Connection c(ip_address, port);
do_smth(f, c);
При выходе из области видимости (либо нормально, либо через exception) вызываются деструкторы у объектов f и с, которые закрывают файл и соединение.
В Java деструкторов нет. Как достигнуть такого же поведения?
Пробовал писать так:
File f = new File("myfile.txt");
Connection c = new Connection (ip_address, port);
try {
do_smth(f, c);
}
finally {
c.close;
f.close;
}

Но это подозрительно похоже на ручной malloc/free-C-style 20-летней давности. Зачем мне самому писать close, разве компилятор сам не может это сделать?
Закроется ли файл f, если возникнет исключение в конструкторе c? Методе c.close?
Кроме того, если у меня большая глубина вызовов, и при этом каждая функция в середине может выделять какие-то ресурсы, то нужно ловить исключения во всех функциях, в одной верхней недостаточно? :confused:
PS. Как обстоит дело в других языках?

pitrik2

ну блин
почитай что такое сборка мусора

nikita270601

лол

danilov

В данном случае это плохо... Оно не гарантирует немедленного уничтожения. Да и финалайзерами лучше не пользоваться.
Лучше это сделать руками. Это надёжно.

Landstreicher

> ну блин
> почитай что такое сборка мусора
Не понимаю, как это связано с моим вопросом :confused:
Мне нужно закрыть файл сразу, после выхода из функции. Допустим, у меня лимит на число открытых файлов или соединений, и мне это важно.

pitrik2

в том же С++ не всегда можно обойтись стеком
зачастенько юзаем new
разве на каждый new должен быть delete?
и этот delete разве не нужно вызывать в finally?
почему тебе это не напоминает "ручной malloc/free-C-style 20-летней давности"?

pitrik2

В данном случае это плохо... Оно не гарантирует немедленного уничтожения. Да и финалайзерами лучше не пользоваться.
Лучше это сделать руками. Это надёжно.
бля
ты нах мои слова извратил?
я ему не советовал читать про финалайзеры
я ему советовал почитать что сборка мусора может произойти когда угодно и потому надо делать руками по факту

nikita270601

В общем, ответ: только описанный способ решает указанную задачу в Java.

danilov

> я ему советовал почитать что сборка мусора может произойти когда угодно и потому надо делать руками по факту
только я не увидел этого подтекста?

Landstreicher

> зачастенько юзаем new
> разве на каждый new должен быть delete?
А чего, auto_ptr/shared_ptr/еще_всякий_разный_ptr уже отменили?

Landstreicher

> В общем, ответ: только описанный способ решает указанную задачу в Java.
Точно? IMHO это как-то не круто. Неужели нельзя автоматизировать написание всех этих try/finally/close? Вон в C++ же как-то сделали.
Тогда еще вопросы:
1) Закроется ли файл f, если возникнет исключение в конструкторе c? Методе c.close?
2) Если ответ — нет, как правильно делать?
3) Как обстоит дело в других языках?

danilov

Можно создать абстрактный класс, оборачивающий абстарактный метод этой обёрткой и наваять имплементаций через анонимусов. Но хоть это и короче,
такой код, имхо, хуже.

pitrik2

А чего, auto_ptr/shared_ptr/еще_всякий_разный_ptr уже отменили?
а нельзя эти самые механизмы в java реализовать?

Landstreicher

Можно пример кода, плз?

Landstreicher

> а нельзя эти самые механизмы в java реализовать?
Наверное, нельзя, для этого деструкторы нужны, а в Java их нет.

danilov

1. Александреску настоятельно рекомендует не делать конструкторов, кидающих исключений (есть вопрос по C++)
В Жаве это тоже хорошая практика.
2. Если без этого нельзя, нужно отделить создание от инициализации, либо создать фабрику... всё как плюсах

pitrik2

1) Закроется ли файл f, если возникнет исключение в конструкторе c? Методе c.close?
2) Если ответ — нет, как правильно делать?
3) Как обстоит дело в других языках?
1) new File не открывает файл
значит искл. в конструкторе ничего не напортит
если в c.close то не закроется
2) правильно оборачивать каждый кусочек который может "слетать" в finally

File f = new File("myfile.txt");
Connection c = new Connection (ip_address, port);
try {
do_smth(f, c);
}
finally {
try {
c.close;
} finally {
f.close;
}
}

vall

1) нет
2) например наворотить два try - finally

pitrik2

Наверное, нельзя, для этого деструкторы нужны, а в Java их нет.
я имею ввиду вот что: можно намутить все что угодно
например: все создаваемый объекты класть куданить
отдельный поток может например постоянно брать оттуда и очищать ресурсы
также это может быть не отдельный поток, а например метод создания ресурсов
например, посмотри как работают коннекшн пулы
вощем все зависит от задачи

danilov


public abstract class CHandler {
  private Connection c;
  private File f;

  public CHandler(Connection c, File f) {
    this.c = c;
    this.f = f;
  }

  protected abstract void doSmth;

  public void handle {
    try {
     doSmth;
    }
    finally
    {
     c.close;
     f.close;
    }
  }

  public static void usage {
    File f = new File("myfile.txt");
    Connection c = new Connection (ip_address, port);
    new CHandler(c, f) {
     protected void doSmth {
     // Сюда пишем.
     }
    }.handle;
  }
}

pitrik2

Можно пример кода, плз?

abstract class A {
protected abstract void _do;

public void do {
try {
// open resources
_do;
} finally {
// close resources
}
}
}

Landstreicher

> 1. Александреску настоятельно рекомендует не делать конструкторов, кидающих исключений (есть вопрос по C++)
Ты точно уверен, что не путаешь с деструкторами? IMHO как раз рекомендуют (например, Страуструп) делать конструкторы с исключениями вместо init.

pitrik2

IMHO как раз рекомендуют (например, Страуструп) делать конструкторы с исключениями вместо init.
правда что ли?
ну тогда это одно из тех мест где идеалогии джавы и с++ различаются

pitrik2

3) Как обстоит дело в других языках?
я все равно продолжаю настаивать что если ты используешь new/delete
то java и c++ тут равны
ну и остальные языки естессно тоже также

6yrop

Как обстоит дело в других языках?
в C#

using (File f = new File("myfile.txt"
{
using(Connection c = new Connection (ip_address, port
{
do_smth(f, c);
}
}

исключения в конструкторе это не покрывает, но есть предположение, что файл не открывается в конструкторе.

Landstreicher

ЖЭСТЬ! Неужели так пишут? Это же какой-то C получается:

fd = open("myfile.txt", O_RDONLY);
if (fd >= 0) {
p = malloc(200);
if (p) {
free(p);
}
close(fd);
}

danilov

В том-то и дело...
Код не очень читаем. Единственный плюс - отсутствие дублирования кода.
Хотя хз. Не использовал такие конструкции

Landstreicher

> правда что ли?

vall

using это такой syntax sugar для try finally?

pitrik2

ты привел явно не ту цитату
там не написано, что использовать исключения в конструкторе это хорошо
там лишь написано что вместо init лучше использовать конструктор, а про исключения ни слова

6yrop

да, но он опирается на системный интрефей IDisposable. В Java такого интерфейса кажись нет.

kokoc88

я все равно продолжаю настаивать что если ты используешь new/delete
то java и c++ тут равны
По этой теме я уже написал кучу постов. :) Си++ удобнее в плане работы с ресурсами, в этом он превосходит и Java, и даже C#. Что касается new и delete, то Java и Си++ равны до тех пор, пока ты не начал пользоваться деструкторами. Любой захват ресурса в Си++ идёт через конструктор-деструктор, что спасает от любых проблем.

Dasar


using (File f = new File("myfile.txt"
{
using(Connection c = new Connection (ip_address, port
{
do_smth(f, c);
}
}

лучше так

using (File f = new File("myfile.txt"
using(Connection c = new Connection (ip_address, port
{
do_smth(f, c);
}

6yrop

отличие только в скобочках?

tipnote

PS. Как обстоит дело в других языках?
Ну, в питоне нет "new/delete", а синтаксический сахар, заменяющий try/finally в работе с ресурсами выглядит так:

with file('file1') as f:
do_with(f)

вложенность в однострочник не раскладывается, ну то есть можно попытаться сэмулировать что-то вроде

with (file('file1') as f1, file('file2') as f2) :
do_with(f1,f2)

на первый взгляд... и для этого нужно сильное "колдунство" с контекстом. Хотя, может и нельзя...

Dasar

> отличие только в скобочках?
да )
так лучше передается, что для выполняемого блока нужны оба ресурса

Maurog

так лучше передается, что для выполняемого блока нужны оба ресурса
дело вкуса, конечно, но я позволю себе не согласиться :grin:
у меня ощущение, что первая строчка ошибочно расположена..возможно плохо закопи-пастили откуда-то код :grin:
Оставить комментарий
Имя или ник:
Комментарий: