Ш̴̴̜̥͍͕̼̙̱͙͎͍̘̀̐̔́̾̃͒̈̔̎́́͜р̧̛̺͖͖̯̖ͧͤ͋̅̽ͧ̈̐̽̆̐͋ͤͦͬ͛̃̑͞͞и̒ͥͤͯ͂ͣ̐̉̑ͫ̉̑҉̛͏̸̻͕͇͚̤͕̯̱̳͉ͅф̴̴̡̟̞͙̙̻͍̦͔̤̞̔̓́̍͗̚͢͞ͅт̨̐ͫ̂͊̄̃ͥͪ͏̫̺͍̞̼͈̩̥̜͔͜͜ы̸̴̱̺̼̠̦͍͍͍̱̖͔̖̱͉̅͑͌͒ͫ͒̀ͥ͐ͤ̅͘̕.̵̴̡̭̼̮͖͈̙͖͖̲̮̬͍͙̼̯̦̮̮ͦ̆̀̑̌ͮͧͣͯ̔̂́͟г͌ͮ̏̈͂ͯ̚҉̛̙̬̘̲̗͇͕̠̙͙̼̩͚̀͘͞ͅо̷̥̯̘̓ͤ̽͒̋̉̀̂̄̒̓̊ͨ͛́̌ͤ̂̀͠в̶̒͒̓̏̓̚҉̛̙̘̺̰̮̼̟̼̥̟̘̠̜͜н̸̷̸̲̝͈͙̰̟̻̟̰̜̟̗͎̻̻͍̿̔̃ͨ͑о̔̀̋ͫ̇̿̐ͫ͌͗ͩ҉̨̜̙̙͈͍̮̮̼̙̘̞̕͜͡ Войти !bnw Сегодня Клубы

У меня вопрос, но начну с введение в то как я до него дошёл.
Допустим, у нас есть какой-то коллбэк, в качестве примера возьмём FutureCallback из всячески уважаемой мной библиотеки HttpCore.
Допустим также, что мы угорели по асинхронности и поэтому после того как коллбэк завершил свою работу, мы хотим сообщить об этом куда следует. Например, чтобы там новый запрос запустили или ещё чего.
Наивная имплементация будет выглядеть примерно так:

public class CompletingFutureCallback<T> implements FutureCallback {
    private final FutureCallback<? super T> callback;
    private final Runnable completionCallback;

    public CompletionFutureCallback(
        final FutureCallback<? super T> callback,
        final Runnable completionCallback)
    {
        this.callback = callback;
        this.completionCallback = completionCallback;
    }

    @Override
    public void cancelled() {
        callback.cancelled();
        completionCallback.run();
    }

    @Override
    public void completed(final T result) {
        callback.completed(result);
        completionCallback.run();
    }

    @Override
    public void failed(final Exception e) {
        callback.failed(e);
        completionCallback.run();
    }
}

Зоркий глаз сразу скажет: А что если коллбэк был написан говнокодером и он кинет unchecked exception в ответ на вызов cancelled, completed или failed? Тогда completionCallback вызван не будет. Ладно, переделаем на finally. Далее уже рассматриваем рефакторинг одной функции, благо все они однотипные:

@Override
public void cancelled() {
    try {
        callback.cancelled();
    } finally {
        completionCallback.run();
    }
}

Зоркий глаз возразит ещё раз: А что если оба коллбэка написаны одним и тем же говнокодером и completionCallback.run() так же кинет unchecked exception? Да, после того как unchecked exception кинул callback.cancelled(). Даже если мы где-то снаружи ловим все Throwable, то информация о первом эксепшене будет безвозвратно потеряна.
В этот момент перфекционист вырывает клок волос из головы и призывает в помощь try-with-resources:

class Completer implements AutoCloseable {
    private final Runnable completionCallback;

    public Completer(final Runnable completionCallback) {
        this.completionCallback = completionCallback;
    }

    @Override
    public void close() {
        completionCallback.run();
    }
}

public class CompletingFutureCallback<T> implements FutureCallback<T> {
    …
    @Override
    public void cancelled() {
        try (Completer completer = new Completer(completionCallback)) {
            callback.cancelled();
        }
    }
    …
}

Вот теперь всё предельно корректно:
Если callback кинет исключение, то completer.close() так же будет вызван, и если он также кинет исключение, то это второе исключение будет добавлено к первому в список suppressed и при печати стек-трейса его будет видно и можно будет поанализировать.
Ну а если callback отработал как следует, то completer.close() так же будет вызван, а если исключение, if any, будет также проброшено наружу.

#KIFEAY / @hirthwork / 3527 дней назад

А теперь собственно вопрос: доктор, меня вылечат?

#KIFEAY/V8O / @hirthwork / 3527 дней назад
@hirthwork Вряд ли.
#KIFEAY/A7H / @pxqr --> #KIFEAY/V8O / 3527 дней назад
У нас было 10 гигабайтов жийсона, чемодан жавы, куча библиотека написаных говнокодерами и целое множество эксепшенов всех сортов и расцветок. <...> Единственное что вызывало у меня опасение - это эксепшены. Нет ничего более беспомощного, безответственного и испорченного, чем баги от эксепшенов. Я знал, что рано или поздно мы перейдем и на эту дрянь.
#KIFEAY/GD6 / @mugiseyebrows / 3527 дней назад
@mugiseyebrows mfw гигабайт жысонов
#KIFEAY/0YE / @pxqr --> #KIFEAY/GD6 / 3527 дней назад

@pxqr на самом деле жсоны у нас редко больше тридцати мегов, хотя гиговые тоже приходили

#KIFEAY/TSL / @hirthwork --> #KIFEAY/0YE / 3527 дней назад
@pxqr бля я иксемель имел ввиду, а написал жсон, ну я даун каэш
#KIFEAY/RNO / @mugiseyebrows --> #KIFEAY/0YE / 3527 дней назад

@mugiseyebrows жысон значительно компактнее хмля

#KIFEAY/VYU / @hirthwork --> #KIFEAY/RNO / 3527 дней назад
ipv6 ready BnW для ведрофона BnW на Реформале Викивач Котятки

Цоперайт © 2010-2016 @stiletto.