Разработка языка с Контролируемыми исключительными ситуациями

Я хорошо знаю о целом аргументе, являются ли контролируемые исключительные ситуации хорошей идеей, и я падаю на сторону, которая они..., но это не точка этого вопроса. Я нахожусь в процессе разработки довольно простого скомпилированного языка ООП, и я решил использовать контролируемые исключительные ситуации в основном в качестве способа возвратить ошибки, не спускаясь по маршруту C возврата кодов ошибок.

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

Возможно, это могло быть дополнительным для ловли исключений и поэтому если бы Вы не пойманы, программа отказала бы? Или возможно могла быть определенная нотация, чтобы обозначить, что исключение не обрабатывается (как виртуальная функция C++ '= 0' нотаций)? Или я мог даже заставить программу отказывать, если обработчик исключений пуст (хотя это могло бы удивить программистов, плохо знакомых с языком)?

Как насчет попытки... ловят синтаксис, Вы думаете, что мог быть более краткий способ выразить, что исключение поймано? Язык будет использовать сборщик "мусора", во многом как Java, так там какая-либо потребность в наконец пункт? Наконец, что другие недостатки там к контролируемым исключительным ситуациям и какие потенциальные решения (если таковые имеются) существуют?

7
задан Stephen Cross 9 February 2010 в 12:18
поделиться

6 ответов

Создайте намерение с действием ACTION _ GET _ CONTENT и установите тип « image/* ». В результате будет запущена операция выбора фотографий. Когда пользователь выбирает изображение, для получения результатов можно использовать обратный вызов onActivityResult .

Что-то вроде:

Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT);
photoPickerIntent.setType("image/*");
startActivityForResult(photoPickerIntent, 1);

protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK)
    {
        Uri chosenImageUri = data.getData();

        Bitmap mBitmap = null;
        mBitmap = Media.getBitmap(this.getContentResolver(), chosenImageUri);
        }
}
-121--3044034-

относительно первого ответа выше, я хотел бы отметить, что условные запросы имеют такой же смысл в динамическом содержимом, как и в статическом. Если код, который генерирует динамическое содержимое, знает, что бэкэнд- сущность (например, предмет базы данных) не изменился, он должен послать 304 по условному запросу.

Ян

-121--2986140-

Мне хорошо известен весь спор о том, являются ли проверенные исключения хорошей идеей, и я считаю, что они...

FWIW, я согласен - по большому счету, они хорошая вещь (tm). Вредные привычки программистов вокруг использования функции не обязательно означают, что функция вредна. В большинстве случаев, я думаю, программисты не понимают, что могут взять пас на исключение и сбить его в цепочку.

Возможно, было бы необязательным перехватывать исключения, и, следовательно, если один из них не пойман, программа потерпит крах?

Java имеет эту функцию ( Исключение RuntiveException и его подклассы являются исключениями без флажков).

Или, возможно, может быть конкретная нотация для обозначения того, что исключение не обрабатывается...

Java имеет это; помещает предложение в объявление метода.

Как насчет синтаксиса try... catch, как вы думаете, может ли быть более сжатый способ выражения того, что вылавливается исключение?

При условии, что он может чувствовать себя немного неуклюжим, но цель состоит в том, чтобы учесть исключительные условия из основной логики.

Однако у меня есть несколько предложений для try.. catch :

catch.. from

Это то, что я хотел на Java и родственных языках в течение длительного времени (действительно нужно написать это правильно и отправить JSR): catch... from .

Вот пример:

FileOutputStream    output;
Socket              socket;
InputStream         input;
byte[]              buffer;
int                 count;

// Not shown: Opening the input and output, allocating the buffer,
// getting the socket's input stream

try
{
    while (/* ... */)
    {
        count = input.read(buffer, 0, buffer.length);
        output.write(buffer, 0, count);

        // ...
    }
}
catch (IOException ioe from input)
{
    // Handle the error reading the socket
}
catch (IOException ioe from output)
{
    // Handle the error writing to the file
}

Как вы видите, цель здесь состоит в том, чтобы разделить несвязанную обработку ошибок для ошибок чтения сокета и ошибок записи файла. Очень основная идея, но есть много тонкостей. Например, исключения, создаваемые другими объектами, используемыми под прикрытием экземпляром выходного потока сокета или файла, должны обрабатываться, как если бы они передавались этим экземпляром (не так уж и трудно, просто необходимо убедиться, что информация об экземпляре находится в трассировке стека).

Это то, что может делать с существующими механизмами и строгими руководящими принципами кодирования, но это очень сложно.

Несколько выражений захвата в одном блоке

A 'la запланированные расширения JDK7.

Повторить

Очень, очень трудно обеспечить, чем выше, а также гораздо легче для людей работать вокруг, так что стоимость намного ниже. Но: Предоставьте семантику «повтора»:

try
{
    // ...stuff here...

    if (condition)
    {
        foo.doSomething();
    }

    // ...stuff here...
}
catch (SomeException se)
{
    if (foo.takeRemedialAction() == Remedy.SUCCESS)
    {
        retry;
    }

    // ...handle exception normally...
}

Здесь doSomething может потерпеть неудачу в исключительном пути,но в путь, который takeRemedyalAction может быть исправлен. Это продолжает тему удержания исключительных условий из основной линии логики. Естественно, retry возвращает выполнение к неудачной операции, которая может находиться глубоко в doSomething или в каком-либо вызываемом субметоде. Ты понимаешь, что я имею в виду о проблемах.

Это гораздо проще для команд, чтобы сделать с существующими механизмами: Просто сделать подпрограмму, которая doSomething плюс takeRemovateAction на исключение, и поместить этот вызов в логику главной линии вместо. Итак, этот низкий в списке, но эй...

1
ответ дан 6 December 2019 в 10:49
поделиться

Думаю, вам стоит прочитать пост Нила Гафтерса об улучшенной обработке исключений в jdk7 и интервью с Андерсом Хьелсбергом об обработке исключений на C# (vs. Java)

.
2
ответ дан 6 December 2019 в 10:49
поделиться

Я думаю, вам следует рассмотреть возможность использования монады с тремя состояниями, такой как тип Lift's Box, для обработки ошибок. Тогда вам вообще не нужно будет использовать исключения.

http://github.com/dpp/liftweb/blob/master/framework/lift-base/lift-common/src/main/scala/net/liftweb/common/Box.scala

2
ответ дан 6 December 2019 в 10:49
поделиться

Я не вижу другого способа связать блок кода с возможными ошибками. Я думаю, что блок try .. catch согласован. В Ruby, в качестве улучшения, есть ключевое слово, которое позволяет повторить блок кода, который был неудачным, это хорошее улучшение, я думаю

0
ответ дан 6 December 2019 в 10:49
поделиться

Проверенные исключения - это всего лишь небольшой пример более общего стремления к тому, что Эрик Мейер назвал честностью типа . Т.е. процедуры, методы, функции не должны совпадать с их типами. Если вы видите подпись типа, вы можете доверять ее типу.

Это неверно для Java сегодня (особенно если вы представляете Java - без проверенных исключений).

Если у вас есть подпись типа, подобная этой в Java:

Foo bar(Baz)

она говорит: «Я беру Baz в качестве входных данных и создаю Foo в качестве выходных». Но это ложь.

Фактически, bar принимает в качестве входных данных либо a Baz , либо null . В качестве входных данных он также принимает полное глобальное состояние, состояние класса и состояние экземпляра, а также весь юниверс (например, файловый ввод-вывод, сетевой ввод-вывод, ввод-вывод базы данных и т. Д. ). И он также не создает Baz в качестве вывода: он создает либо a Foo , либо null , либо исключение ] или Нижний (т. е. вообще ничего). Плюс его вывод также включает в себя все глобальное состояние, все состояние класса, все состояние экземпляра, а также все состояние вселенной.

bar фактический тип:

(IO<Foo | null | Exception> | Bottom) bar(IO<Baz | null>)

или что-то в этом роде.

Это необходимо исправить, и проверенные исключения являются (очень маленькой) частью этого. Я лично считаю, что другие части более важны, и разработчикам Java следовало сосредоточиться на исправлении тех , а не исключений (тем более, что исключения в любом случае являются лишь побочными эффектами, и поэтому вы фактически автоматически исправляете исключения для бесплатно при исправлении побочных эффектов).

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

Как исправить отмеченные исключения во многом зависит от того, что именно вы считаете на самом деле неправильным с ними.

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

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

При использовании проверенных исключений, реализованных в Java, каждый фрагмент кода между и должен быть изменен.

Одно из предложений по устранению этой проблемы - это Объявления привязанных исключений . (Улучшено в Модульные объявления с привязкой к исключениям .)

Идея объявлений с привязкой к исключениям в основном заключается в использовании делегирования для объявлений исключений так же, как делегирование в теле метода. , что, в конце концов, и создает проблему в первую очередь.

Допустим, у вас есть метод чтения файлов, который делегирует другому методу:

String fileReader(String filename) {
  return this.fileHelper.read(filename);
}

Теперь вы входите в JavaDoc для FileHelper # read и вырезаете и вставляете список исключений в свой метод:

String fileReader(String filename) throws IOException, CustomFileReaderEx

Теперь автор из FileHelper # read решает, что он использует другую стратегию реализации. Теперь он гарантирует, что фактическое чтение файла никогда не завершится ошибкой, сначала убедившись, что файл существует, может быть открыт и имеет правильный формат. Так что, естественно, меняется набор исключений. Больше невозможно получить исключение IOException или CustomFileReaderEx .Вместо этого вы можете получить InvalidFilenameEx или CorruptDataEx . Итак, вы снова копируете и вставляете:

String fileReader(String filename) throws InvalidFilenameEx, CorruptDataEx

Не только вы должны были внести это изменение, но и все, кто вызывает fileReader (и все, кто их вызывает, и все, кто их вызывает, и. ..) также. Это безумие! Причина, по которой вы делегировали вызов fileHelper в первую очередь, заключалась в том, что вам не нужно беспокоиться об этих деталях.

Итак, идея закрепленных объявлений исключений состоит в том, чтобы использовать это делегирование для самих объявлений исключений. Вместо того, чтобы говорить, какие точные исключения вы выбрасываете, вы просто обвиняете кого-то другого. «Он сделал это!»:

String fileReader(String filename) throws like this.fileHelper.read

И ваши клиенты просто скажут:

Foo whatever() throws like fileReader

Таким образом, когда FileHelper изменяет свои исключения, то только код , который необходимо изменить, будет код обработки исключений очень верхнего уровня, точно так же, как я описал выше для случая unchecked .

Конечно, есть ограничения. Например, чтобы не нарушить инкапсуляцию, вы можете использовать только идентификаторы в ваших бросках , например , которые доступны всем вашим клиентам. Если в этом случае fileHelper является частным полем, вы не можете его использовать. Вам понадобится другой способ. Например, если класс FileHelper является общедоступным (или если это частный пакет и , все ваши клиенты находятся в одном пакете), вы можете вместо этого сказать

String fileReader(String filename) throws like FileHelper.read

. В документе перечислены и другие ограничения.(Один из них поднимается в статье о модульных объявлениях привязанных исключений.)

В любом случае, это один способ решить некоторые проблемы с проверяемыми исключениями. Однако проверенные исключения существуют уже почти 40 лет, и мы до сих пор не поняли их, так что это , очевидно, сложная проблема.

13
ответ дан 6 December 2019 в 10:49
поделиться

Механизм обработки исключений языка программирования CLU полностью проверен и рассчитан на безупречную надежность.Поскольку почти все современные механизмы исключений являются более разрешительными версиями исходной модели CLU, их стоит внимательно изучить. Если у вас есть доступ к хорошей библиотеке, вам стоит прочитать статью Лискова и Снайдера .

Что касается синтаксиса, есть превосходная статья Ника Бентона и Эндрю Кеннеди , в которой объясняются слабые места стандартного синтаксиса и предлагаются новые интересные варианты. Это обязательное чтение для всех, кто занимается дизайном в этой области.

0
ответ дан 6 December 2019 в 10:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: