Опирается на правила:
JS-4.1…JS-4.7из Java Style Guide → раздел 4. Выражения.
Важно знать
- Сложность булева — не более 3 операторов
&&/||в одном выражении.- Java-стиль массивов:
int[] nums, неint nums[].- Порядок модификаторов:
public/protected/private → static → final → transient → volatile → synchronized.- Не указывать неявные:
public abstractв методах интерфейса;staticво вложенных enum.- Method reference вместо лямбды, где имеет смысл (
list::contains).- Большие лямбды (> 1 выражения) — вынести в named method.
- Guard expression вместо вложенных условий — early return.
Выражения — место, где «работает, но плохо читается» накапливается. UCP формулирует правила так, чтобы выражение сразу говорило о намерении — early return, method reference, явный порядок модификаторов.
Сложность булева
JS-4.1: ≤ 3 операторов.
// ✓ — 3 оператора
boolean valid = (!a && b) | (a || !b) ^ a;
// ✗ — 4 оператора, нечитаемо
boolean bad = (a && b) && c && (c || b);
3 операторов = декомпозируем в named-переменные или выносим в method:
// ✓ — named-переменные
var ageValid = age >= 18 && age <= 65;
var statusValid = status == Status.ACTIVE || status == Status.PENDING;
var locationValid = country.equals("RU") || country.equals("BY");
if (ageValid && statusValid && locationValid) {
// ...
}
// или в method
private boolean isEligibleForBonus(User user) {
if (user.age() < 18 || user.age() > 65) return false;
if (user.status() != Status.ACTIVE && user.status() != Status.PENDING) return false;
return user.country().equals("RU") || user.country().equals("BY");
}
Java-стиль массивов
JS-4.2: тип имеет квадратные скобки.
int[] nums; // ✓
String[] strs; // ✓
List<int[]> grids; // ✓
String strs[]; // ✗ — C-стиль
int nums[][]; // ✗ — C-стиль
int[] — это тип «массив int-ов». int nums[] — устаревший C-style, где [] ассоциируется с переменной. В Java тип — целостная единица.
Порядок модификаторов
JS-4.3: фиксированный.
public → protected → private → static → final → transient → volatile → synchronized
public static final String TIMEOUT = "30s"; // ✓
private static final Logger log = ...; // ✓
protected static final int MAX = 100; // ✓
static public final String TIMEOUT = "30s"; // ✗ — порядок нарушен
final public static String TIMEOUT = "30s"; // ✗
JLS не требует, но конвенция помогает быстрее сканировать declarations. IntelliJ имеет inspection «Wrong modifier order» — fix через Alt+Enter.
Не указывать неявные модификаторы
JS-4.4: не дублировать defaults.
public interface OrderService {
void create(CreateOrderCommand command); // ✓ — public abstract неявно
public abstract void create(CreateOrderCommand command); // ✗
}
public interface OrderStatus {
enum Type { DRAFT, CONFIRMED } // ✓ — static неявно во вложенных enum
static enum Type { DRAFT, CONFIRMED } // ✗
}
Контекст:
- Методы интерфейса —
public abstractпо умолчанию (для regular methods, не default/static). - Вложенные enum/interface —
staticпо умолчанию. - Поля интерфейса —
public static finalпо умолчанию.
Не пишем явно — это шум.
Method reference vs лямбда
JS-4.5: short когда возможно.
list.stream()
.filter(someStrings::contains) // ✓ — method reference
.forEach(System.out::println); // ✓
list.stream()
.filter(s -> someStrings.contains(s)) // ✗ — лямбда дублирует method
.forEach(s -> System.out.println(s)); // ✗
Method reference — компактнее, выразительнее. IntelliJ предлагает auto-convert.
Когда не используем method reference:
- Лямбда делает что-то дополнительное к method call:
s -> someStrings.contains(s.toLowerCase())— reference не подходит. - Лямбда вызывает несколько методов:
s -> { validate(s); process(s); }.
Большие лямбды → named method
JS-4.6: > 1 выражения.
// ✗ — большая лямбда inline
list.stream()
.filter(order -> {
if (order.status() != OrderStatus.CONFIRMED) return false;
var diff = Duration.between(order.createdAt(), Instant.now());
return diff.toDays() > 7 && order.totalAmount().compareTo(BigDecimal.ZERO) > 0;
})
.forEach(this::process);
// ✓ — выделили в method, передаём reference
list.stream()
.filter(this::isStaleOrderWithAmount)
.forEach(this::process);
private boolean isStaleOrderWithAmount(Order order) {
if (order.status() != OrderStatus.CONFIRMED) return false;
var ageInDays = Duration.between(order.createdAt(), Instant.now()).toDays();
return ageInDays > 7 && order.totalAmount().compareTo(BigDecimal.ZERO) > 0;
}
Преимущества:
- Имя объясняет назначение (
isStaleOrderWithAmount). - Testable — method можно unit-test-ить.
- Reuse — same logic из другого места.
- Stack trace — exception показывает имя method, не lambda$lambda$...
Guard expression
JS-4.7: early return.
// ✓ — guard pattern, early return на ошибки
public void process(Order order) {
if (!order.isValid()) {
throw new InvalidOrderException(order.id());
}
if (order.status() == OrderStatus.CANCELLED) {
throw new OrderCancelledException(order.id());
}
doProcess(order);
publish(order);
notify(order);
}
// ✗ — nested else с throw
public void process(Order order) {
if (order.isValid()) {
if (order.status() != OrderStatus.CANCELLED) {
doProcess(order);
publish(order);
notify(order);
} else {
throw new OrderCancelledException(order.id());
}
} else {
throw new InvalidOrderException(order.id());
}
}
Guard expression — все check-условия наверху method-а с early return / throw, основная логика — без вложенности. Это:
- Снижает максимальную indentation на 2 уровня.
- Делает «happy path» очевидным внизу.
- Каждый guard — отдельный assertion, легко добавить новый.
Применяется к public-методам где входные данные могут быть невалидными. Для internal methods — guard опционален.
Что запрещено
| Антипаттерн | Правило | Что взамен |
|---|---|---|
| Boolean expression > 3 операторов inline | JS-4.1 | named-переменные или method |
int nums[] C-стиль | JS-4.2 | int[] nums |
| Произвольный порядок модификаторов | JS-4.3 | public static final ... |
public abstract в interface method | JS-4.4 | без неявных модификаторов |
s -> list.contains(s) | JS-4.5 | list::contains |
| Большая inline-лямбда | JS-4.6 | named method + reference |
| Nested if-else с throw в else | JS-4.7 | guard expression + early return |
if (...) { return; } else if (...) ... | JS-4.7 | early return без else |
Boolean expression с && и || без скобок | JS-4.1 | явные скобки |
Куда дальше
- Java → раздел 4. Выражения — нормативные формулировки.
- Именование — имена методов для extracted lambdas.
- Современные фичи Java — switch expressions, record patterns.
- Lombok —
@RequiredArgsConstructorубирает явный ctor. - Отступы и форматирование — длина строки, перенос.
- Error handling → exception hierarchy — для guard expressions.