Java Code Review by trydofor

website·Indexed 31 days ago

https://java-code-review.moilioncircle.com

A comprehensive guide to Java code quality, focusing on team rules, technical debt, and engineering practices. It covers coding styles, naming conventions, static and dynamic analysis (including CheckStyle), exception handling (NPE), side effects, and referential transparency. The site also features a 'Technical Debt' section analyzing real-world code examples and recommends resources like Effective Java 3rd Edition and the WingsBoot SpringBoot scaffold.

Tokens
9.9K
Snippets
32
Records
79
Agent score
49%

What's inside Java Code Review

  1. Separate business logic from MVC Controllers

    To maintain a clean architecture, business logic and database operations should be placed in the Service layer. The Controller (MVC 'C' layer) should be restricted to data validation, data transformation, and orchestrating calls to the Service layer.
  2. Handle date and time calculations using Java 8+ Temporal API

    Avoid treating date calculations as simple arithmetic (e.g., adding months and days manually) because date operations do not follow commutative laws. Use TemporalAdjusters and explicit methods like minusMonths() instead of plusMonths(-n). Ensure time-zone handling is centralized rather than manually adjusting hours (e.g., avoid minusHours(8)).
    final LocalDate endDate = LocalDate.now();
    LocalDate startDate = endDate
            .minusWeeks(4)
            .with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY));
    final LocalDate firstDayOfYear = endDate.with(TemporalAdjusters.firstDayOfYear());
    if (startDate.isBefore(firstDayOfYear)) {
        startDate = firstDayOfYear;
    }
  3. Define explicit return types for public API interfaces

    Avoid using wildcard return types like R<?> in public controller methods. Explicitly defining the return type ensures that Swagger can automatically generate accurate API documentation and guarantees data consistency during deserialization.
    // Avoid
    public R<?> getLineChartWeeks() { ... }
    
    // Prefer
    public R<LineChartWeeksResponse> getLineChartWeeks() { ... }
  4. Replace long parameter lists with Request Objects

    Avoid controllers with long lists of @RequestParam arguments. Instead:

    • Use @RequestBody BizIns ins to encapsulate business data.
    • Use @PageDefault(size = 20) PageQuery pq for query string parameters to leverage alias functionality.
    • Use primitive boolean instead of Boolean for mandatory flags to prevent null values.
    • Use JSON wrapping for business data to better support the parsing of enums and date-time types.
  5. Improve code readability through variable extraction

    Enhance the clarity of business logic by extracting frequently used method calls into local variables. For example, instead of calling po.getStatus() multiple times within complex if statements, extract the value into a final variable to ensure immutability and improve conciseness.
  6. Use @Param.Out and @Param.InOut to signal parameter mutation

    Use @Param.Out and @Param.InOut annotations on method parameters to explicitly warn the caller that the passed object/collection will be modified within the method (similar to in and out modifiers in C#).
    void create(
        @NotNull OwtLadingMain owtLadingMain, 
        @Param.Out List<OwtLadingOrder> owtLadingOrdersOut, 
        @Param.InOut List<OwtLadingExpress> owtLadingExpressesInOut
    );
  7. Manage class members and inheritance depth

    To preserve the Single Responsibility Principle and encapsulation:

    • Class Members: Limit the number of fields and methods to approximately 10. Members following the same pattern (e.g., polymorphic methods or similar rule injections) can be grouped as one type.
    • Inheritance: Limit inheritance depth to 3 generations (excluding framework interfaces). This avoids excessive Override chains and deep super.invoke() calls.
  8. Choose the appropriate method for object cloning and DTO mapping

    When copying values between DTOs or cloning objects, use the following priority (from highest to lowest efficiency/safety):

    1. MapStruct: Strong typing, compile-time static assignment.
    2. BeanUtil: Weak typing, runtime reflection-based assignment or shallow clone.
    3. Serialization/Deserialization: Weak typing, deep copy (Kryo is preferred over JSON).
  9. Optimize Cacheable and JOOQ query implementation

    When implementing cached data retrieval and JOOQ queries:

    • Use predefined constants for @Cacheable(value = ...) instead of hardcoded strings.
    • Use StateAssert.notNull() for CodeException checks instead of Optional in non-reactive flows.
    • Use Lombok's @Slf4j for logging.
    • In JOOQ, avoid using static table instances; use the DAO with lambda expressions for simple queries to ensure correct alias handling.
    @Cacheable(value = UserDetail.CacheNameDetail)
    public OwtUserDetail getByUserIdFromCache(Long id) {
        log.debug("find from db");
        final OwtUserDetail detail = owtUserDetailDao.fetchOne(t -> t.onlyLive(t.UserId.eq(id)));
        StateAssert.notNull(detail, CommonErrorEnum.AssertNotFound1, id);
        return detail;
    }
  10. Optimize SLF4J logging to avoid unnecessary serialization

    Avoid calling expensive methods like JSONObject.toJSONString() directly inside a logger call. Because the method executes before the logger checks if the log level is enabled, it causes unnecessary performance overhead and memory fragmentation. Use an if (logger.isInfoEnabled()) guard or the Fluent API with a lambda for lazy evaluation.
    // Recommended: Guard with log level check
    if (logger.isInfoEnabled()) {
        logger.info("truck rate {}", JSONObject.toJSONString(request));
    }
    
    // Alternative: Fluent API with lambda (SLF4J 2.0+)
    logger.atInfo()
        .setMessage("truck rate {}")
        .addArgument(() -> JSONObject.toJSONString(request))
        .log();
  11. Implement Static Code Analysis for Java projects

    Static Code Analysis is recommended to eliminate approximately 80% of low-quality code. The following tools are recommended for static analysis: CheckStyle, SpotBugs (formerly FindBugs), and PMD. When using multiple tools or rules that conflict, the team's established rules should take precedence over tool defaults.