AtomicBoolean в однопоточной среде

Рейтинг: 1Ответов: 2Опубликовано: 08.06.2023

У меня такой вопрос, является ли использование AtomicBoolean в однопоточном приложении плохой практикой? Я использовал его из-за удобных и читаемых методов.

У меня в методе вычитываются данные из таблицы пакетами, коллекция кладется в функцию, которая передается далее на insert. Результат insert это тоже boolean, таких insert может быть десятки, все результаты я суммирую с AtomicBoolean result

public boolean readAllInBatch(Function<List<AccDivTypeRBC>, Boolean> function) {
    AtomicBoolean result = new AtomicBoolean(true);
    try {
        List<AccDivTypeRBC> accDivTypeRBCS = new ArrayList<>();
        dsfJdbcTemplate.query(SQL_READ, resultSet -> {
            accDivTypeRBCS.add(AccDivTypeRBC.builder()
                .id(resultSet.getLong(1))
                .name(resultSet.getString(2))
            .build());
            if (accDivTypeRBCS.size() == batchSize) {
                result.set(result.get() && function.apply(accDivTypeRBCS));
                accDivTypeRBCS.clear();
            }
            if (resultSet.isLast()) {
                result.set(result.get() && function.apply(accDivTypeRBCS));
            }
        });
    } catch (Exception e) {
        log.error(e);
        return false;
    }
    return result.get();
}

Ответы

▲ 1Принят

Тема достаточно холиварная. С одной стороны для соблюдения принципов функционального программирования, а именно концепции "чистых функций", лямбда не должна использовать данные из замыкания. С другой стороны ни разу не видел, чтобы такой подход карался либо осуждался. Т.е. пробрасывание локальных переменных в лямбду/анонимный класс для их модификации с использование различных обёрток - это уже норма. Лично я больше склоняюсь к первому варианту.

Что касается вашего примера, то я бы заменил метод с query(String sql, RowCallbackHandler rch) на query(final String sql, final ResultSetExtractor<T> rse), что позволит объявить и использовать булевую переменную внутри лямбды. Список List<AccDivTypeRBC> тоже может созадаваться и использоваться внутри. С Function<List<AccDivTypeRBC>, Boolean> будет сложнее - либо оставить как есть, либо пробрасывать внутрь через функцию обёртку. Это как раз второй вариант - рефакторинг займёт больше времени нежели использование лямбдой параметра из замыкания.

▲ 0

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

Самый популярный костыль для передачи любого значения по ссылке - массив из одного элемента:

boolean[] result = new boolean[1];

Также не забывайте, вы всегда можете сделать удобный вам контейнер сами, в использовании вспомогательных классов нет ничего плохого:

class BooleanBox {
    public boolean value;
}

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

RowCallbackHandler handler = new RowCallbackHandler() {

    private List<AccDivTypeRBC> accDivTypeRBCS = new ArrayList<>();
    public boolean result = true;

    public void processRow(ResultSet resultSet) {
        // …
    }
};

try {
    dsfJdbcTemplate.query(SQL_READ, handler);
    return handler.result;
} catch (Exception e) {
    log.error(e);
    return false;
}