AtomicBoolean в однопоточной среде
У меня такой вопрос, является ли использование 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();
}
Ответы (2 шт):
Тема достаточно холиварная. С одной стороны для соблюдения принципов функционального программирования, а именно концепции "чистых функций", лямбда не должна использовать данные из замыкания. С другой стороны ни разу не видел, чтобы такой подход карался либо осуждался. Т.е. пробрасывание локальных переменных в лямбду/анонимный класс для их модификации с использование различных обёрток - это уже норма. Лично я больше склоняюсь к первому варианту.
Что касается вашего примера, то я бы заменил метод с query(String sql, RowCallbackHandler rch) на query(final String sql, final ResultSetExtractor<T> rse), что позволит объявить и использовать булевую переменную внутри лямбды. Список List<AccDivTypeRBC> тоже может созадаваться и использоваться внутри. С Function<List<AccDivTypeRBC>, Boolean> будет сложнее - либо оставить как есть, либо пробрасывать внутрь через функцию обёртку. Это как раз второй вариант - рефакторинг займёт больше времени нежели использование лямбдой параметра из замыкания.
Нет, атомарные значения в однопоточном приложении сильно плохой практикой не являются. Однако, это не отменяет их избыточности и 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;
}