常用Java工具库


JSON 处理库

处理 JSON 是现代后端和前端交互的核心。主要有两个选择:Gson(Google)和 Jackson(更强大,社区更活跃)

a) Gson (Google)

Gson 非常易于使用,适合简单的序列化(Java对象 -> JSON)和反序列化(JSON -> Java对象)。

示例:

import com.google.gson.Gson;
import com.google.gson.JsonObject;
// 1. 简单的对象转换
class User {
    private String name;
    private int age;
    // ... getters and setters
}
User user = new User("Alice", 30);
Gson gson = new Gson();
// 序列化 to JSON
String json = gson.toJson(user);
System.out.println(json); // 输出: {"name":"Alice","age":30}

// 反序列化 from JSON
String inputJson = "{\"name\":\"Bob\",\"age\":25}";
User userObject = gson.fromJson(inputJson, User.class);
System.out.println(userObject.getName()); // 输出: Bob

// 2. 使用 JsonObject 动态构建JSON(你问题中提到的JsonObject)
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", "Charlie");
jsonObject.addProperty("age", 28);
jsonObject.addProperty("isStudent", false);

String dynamicJson = gson.toJson(jsonObject);
System.out.println(dynamicJson); // 输出: {"name":"Charlie","age":28,"isStudent":false}

b) Jackson

Jackson 是 Spring 框架默认集成的库,功能更强大,支持流式API、注解等,性能也通常更好。

示例:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
ObjectMapper mapper = new ObjectMapper();
User user = new User("David", 40);

// 序列化
String jsonString = mapper.writeValueAsString(user);
System.out.println(jsonString);

// 反序列化
String jsonInput = "{\"name\":\"Eva\",\"age\":35}";
User parsedUser = mapper.readValue(jsonInput, User.class);
System.out.println(parsedUser.getName());

2. 集合、IO、字符串等工具库

Apache Commons Lang & Commons Collections

这个库提供了大量工具方法,弥补了 Java 标准库的不足,尤其是 StringUtils, CollectionUtils等,能让你写出更简洁、健壮的代码。

示例:

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import java.util.Arrays;
import java.util.List;

// 字符串操作
String str = "  hello  ";
System.out.println(StringUtils.isEmpty(str)); // false
System.out.println(StringUtils.trim(str)); // "hello"
System.out.println(StringUtils.abbreviate("This is a long string", 10)); // "This is..."

// 集合操作
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("b", "c", "d");

// 取交集
System.out.println(CollectionUtils.intersection(list1, list2)); // [b, c]
// 判断集合是否为空(安全,避免NPE)
System.out.println(CollectionUtils.isEmpty(null)); // true

Guava (Google)

Google 提供的另一个核心库,功能与 Apache Commons 有重叠,但设计哲学不同,提供了更多不可变集合、函数式编程支持、缓存等高级工具。

示例:

import com.google.common.collect.ImmutableList;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
// 1. 创建不可变集合(线程安全,性能好)
ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");
// immutableList.add("d"); // 这行会抛出 UnsupportedOperationException

// 2. 强大的字符串连接和分割
Joiner joiner = Joiner.on("; ").skipNulls();
String result = joiner.join("Harry", null, "Ron", "Hermione");
System.out.println(result); // "Harry; Ron; Hermione"

// 比 String.split 更灵活
Iterable<String> split = Splitter.on(',')
        .trimResults()
        .omitEmptyStrings()
        .split("foo, bar,,   qux");
split.forEach(System.out::println); // 输出 "foo", "bar", "qux"

3. 日期时间库

Java 8+ java.time(首选)

Java 8 自带的新日期时间 API (java.time包) 已经非常完善,完全可以替代旧的 DateCalendar除非维护老项目,否则应首选这个

示例:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

// 获取当前日期和时间
LocalDate today = LocalDate.now();
LocalDateTime now = LocalDateTime.now();

// 构造特定日期
LocalDate birthday = LocalDate.of(1995, 5, 23); // 注意月份是 1-12

// 日期计算
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
LocalDate yearsAgo = today.minusYears(30);

// 日期格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);
System.out.println(formattedDateTime); // 输出: 2023-10-27 14:30:00

// 解析字符串为日期
LocalDateTime parsedDate = LocalDateTime.parse("2023-10-27 14:30:00", formatter);

Joda-Time (历史选择)

在 Java 8 之前,Joda-Time 是处理日期时间的事实标准。现在官方推荐迁移到 java.time,因为它的设计很大程度上被 Java 8 采纳了。


4. 单元测试库

JUnit 5

现代Java单元测试的标准框架。

示例:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class MyTest {
    @Test
    void testAddition() {
        assertEquals(4, 2 + 2, "2+2 should be 4");
        assertTrue("Hello".startsWith("H"));
    }
}

AssertJ

提供流式断言,让测试代码更流畅、易读。

示例:

import static org.assertj.core.api.Assertions.assertThat;

@Test
void testWithAssertJ() {
    String name = "Michael";
    assertThat(name)
            .isNotBlank()
            .startsWith("Mi")
            .endsWith("ael")
            .hasSize(7);

    List<String> names = Arrays.asList("John", "Jane", "Michael");
    assertThat(names)
            .hasSize(3)
            .contains("Jane")
            .doesNotContain("Bob");
}

5. 日志库

Java 日志体系通常使用 SLF4J 作为门面(接口),LogbackLog4j 2 作为具体实现。这种组合避免了代码和具体日志实现库的耦合。

示例:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClass {
    // 获取Logger对象,通常一个类一个
    private static final Logger LOGGER = LoggerFactory.getLogger(MyClass.class);

    public void doSomething() {
        LOGGER.debug("This is a debug message.");
        LOGGER.info("Method doSomething is called.");
        try {
            // ... some code
        } catch (Exception e) {
            LOGGER.error("An error occurred while doing something", e);
        }
    }
}

总结与推荐

类别 首选推荐 备选/历史选择 核心特点
JSON Jackson Gson 功能强大,Spring默认集成
工具类 Apache Commons Lang, Guava - 填补JDK空白,提供高效工具方法
日期时间 Java 8 java.time Joda-Time 官方现代API,线程安全,设计优良
测试 JUnit 5 + AssertJ JUnit 4 流式断言,表达力强
日志 SLF4J + Logback Log4j 2 门面模式,解耦,灵活配置

给你的建议:

  1. 1.新项目:直接使用 JacksonJava 8 timeJUnit 5SLF4J + LogbackGuava/Apache Commons 的组合,这是目前最主流、最现代的技术栈。
  2. 2.老项目维护:了解项目正在使用的库(可能是 Gson、Joda-Time、JUnit 4),保持一致性,除非你有计划且有能力进行升级重构。

1. 数据库连接池

在 Web 应用中,直接为每个请求创建新的数据库连接开销巨大。连接池负责维护和管理一组数据库连接,使用时从池中获取,用完后归还,极大地提升了性能。

HikariCP

它是目前速度最快、最轻量的连接池,是 Spring Boot 2.x 以后的默认连接池。

示例 (Spring Boot 配置和使用):

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: user
    password: pass
    hikari:
      maximum-pool-size: 10 # 最大连接数
      connection-timeout: 30000 # 连接超时时间(ms)

在你的代码中,你无需直接操作 HikariCP,而是通过 DataSource接口使用它,Spring Boot 会自动注入。

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@RestController
public class MyController {

    @Autowired
    private DataSource dataSource; // 由 Spring 管理的 HikariCP 数据源

    public void doDatabaseOperation() {
        // 从连接池获取连接
        try (Connection connection = dataSource.getConnection()) {
            // 使用 connection 进行数据库操作...
            // ...
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // try-with-resources 语句会自动将 connection.close(),即归还给连接池
    }
}

2. 映射工具 (Object Mapping)

手动在数据库查询结果 (ResultSet) 和 Java 对象之间进行转换非常繁琐。映射工具可以自动完成这项工作。

MapStruct

它是一个基于注解的代码生成器,在编译期生成映射代码,因此性能极高,等同于手写代码。

示例:

定义两个类和一个映射接口。

// 源对象
public class CarDto {
    private String make;
    private int numberOfSeats;
    // ... getters and setters
}

// 目标对象
public class Car {
    private String manufacturer;
    private int seatCount;
    // ... getters and setters
}

定义映射器接口,使用 @Mapper注解。

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper // 编译后,MapStruct 会生成此接口的实现类,如 CarMapperImpl
public interface CarMapper {

    @Mapping(source = "make", target = "manufacturer")
    @Mapping(source = "numberOfSeats", target = "seatCount")
    Car carDtoToCar(CarDto carDto);
}

使用生成的映射器:

// 假设通过依赖注入获取 mapper 实例
CarDto dto = new CarDto("Toyota", 5);
Car car = mapper.carDtoToCar(dto);
// car.getManufacturer() == "Toyota"
// car.getSeatCount() == 5

3. Excel 操作库

在企业应用中,经常需要导入/导出 Excel 文件。

Apache POI

功能最强大、最底层的 Java API,可以操作 .xls 和 .xlsx 格式的 Excel 文件。

示例:创建一个简单的 Excel 文件 (.xlsx):

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelExample {
    public static void main(String[] args) throws Exception {
        Workbook workbook = new XSSFWorkbook(); // 创建新工作簿
        Sheet sheet = workbook.createSheet("Employee Data"); // 创建工作表

        // 创建标题行
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("Name");
        headerRow.createCell(1).setCellValue("Age");

        // 创建数据行
        Row dataRow = sheet.createRow(1);
        dataRow.createCell(0).setCellValue("John Doe");
        dataRow.createCell(1).setCellValue(30);

        // 将工作簿写入文件
        try (FileOutputStream fileOut = new FileOutputStream("workbook.xlsx")) {
            workbook.write(fileOut);
        }
        workbook.close();
    }
}

EasyExcel (阿里开源)

针对 POI 的优化版,解决了 POI 耗内存的问题(通过逐行解析),API 更简单,特别适合处理大文件。

示例:

// 写入Excel
EasyExcel.write("demo.xlsx", DemoData.class).sheet("模板").doWrite(dataList);

// 读取Excel(监听器模式,逐行读取,不耗内存)
EasyExcel.read("demo.xlsx", DemoData.class, new AnalysisEventListener<DemoData>() {
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        // 每读一行数据,都会调用此方法
        System.out.println("读取到一条数据: " + data);
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 全部读取完成
    }
}).sheet().doRead();

4. HTTP 客户端

用于在 Java 代码中发送 HTTP 请求,调用其他服务的 API。

OkHttp

一个高效的 HTTP & HTTP/2 客户端,API 简洁明了。

示例:发送一个 GET 请求

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpExample {
    public static void main(String[] args) throws IOException {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://api.github.com/users/google")
                .build();

        // 同步调用
        try (Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                System.out.println(responseBody);
            }
        }
    }
}

5. 缓存库

在内存中缓存常用数据,避免频繁访问数据库,极大提升应用性能。

Caffeine

一个高性能、高命中率的缓存库,是 Guava Cache 的现代版替代品。

示例:

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

public class CaffeineExample {
    public static void main(String[] args) {
        // 构建缓存
        Cache<String, Object> cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES) // 写入10分钟后过期
                .maximumSize(10_000) // 最大缓存条目数
                .build();

        // 1. 手动操作
        String key = "user:1001";
        // 存入缓存
        cache.put(key, new Object());
        // 从缓存获取,如果不存在则返回 null
        Object value = cache.getIfPresent(key);

        // 2. 自动操作(推荐):如果缓存不存在,则通过Lambda生成值并存入
        Object value2 = cache.get(key, k -> createExpensiveValue(k));
        System.out.println(value2);
    }

    private static Object createExpensiveValue(String key) {
        // 模拟一个耗时/耗资源的操作(如查数据库)
        return "Data for " + key;
    }
}

6. 简化代码的利器

Lombok

通过注解在编译时自动生成 Getter、Setter、构造函数、toString()等样板代码,让代码极其简洁。

示例:

import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@Data // 自动生成 getter, setter, toString, equals, hashCode
@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
public class User {
    private Long id;
    private String name;
    private Integer age;
}

// 使用这个类,你无需写任何 get/set 方法!
public class Main {
    public static void main(String[] args) {
        User user = new User(1L, "Alice", 30);
        System.out.println(user.getName()); // 可以直接调用,Lombok在编译时生成了getName()
        System.out.println(user.toString()); // 输出: User(id=1, name=Alice, age=30)
    }
}

总结表格

类别 推荐库 核心特点 适用场景
数据库连接池 HikariCP 极快、轻量 所有需要数据库连接的 Web 应用
对象映射 MapStruct 编译期生成,性能无敌 DTO、VO、DO 等对象间转换
Excel 操作 Apache POI (全功能) / EasyExcel (大文件) POI 功能全,EasyExcel 省内存 报表生成、数据导入导出
HTTP 客户端 OkHttp API 现代、高效 调用第三方 API、微服务间通信
缓存 Caffeine 高性能、高命中率 缓存热点数据,提升访问速度
代码简化 Lombok 通过注解减少样板代码 所有需要定义 POJO 的项目

Spring Boot项目结构

一个典型的 Spring Boot 项目结构遵循约定大于配置的原则

flowchart TD
    User[用户/客户端]
    subgraph SpringBootApp [Spring Boot 应用]
        C[Controller
控制层] S[Service
业务逻辑层] R[Repository
数据访问层] C -- 调用 --> S S -- 调用 --> R end Database[(数据库)] User -- HTTP请求 --> C C -- HTTP响应 --> User R -- JDBC操作 --> Database Database -- 返回数据 --> R
src/
├── main/
   ├── java/              # 源代码根目录
   │   └── com/
   │       └── example/
   │           └── yourapp/          # 你的项目基包,通常是公司域名反写
   │               ├── Application.java  # 主启动类(核心)
   │               ├── controller/    # 控制层(Web层)
   │               ├── service/        # 业务逻辑层(服务层)
   │               │   ├── impl/       # 服务实现类(可选)
   │               ├── repository/     # 数据访问层(Repository层)
   │               ├── entity/         # 实体类(模型层)
   │               ├── dto/           # 数据传输对象(Data Transfer Object)
   │               ├── config/         # 配置类
   │               └── exception/      # 自定义异常处理
   └── resources/         # 资源文件根目录
       ├── static/        # 静态资源(js, css, images等)
       ├── templates/     # 模板文件(Thymeleaf, Freemarker等)
       ├── application.properties  # 主配置文件(或application.yml)
       └── ...
├── test/
   └── java/              # 测试代码目录(结构通常与main/java镜像)
└── pom.xml                # Maven项目配置文件

1.主启动类 (Application.java)

位置: 位于项目基包的根目录下。

职责: 程序的入口点。包含 main方法,通过 @SpringBootApplication注解启动整个Spring Boot应用。

示例:

package com.example.yourapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 核心注解,开启了组件扫描和自动配置
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args); // 启动嵌入式的Tomcat和应用
    }
}

2. 控制层 (Controller)

位置: com.example.yourapp.controller

职责:接收用户的HTTP请求(GET, POST, PUT, DELETE等)。

调用Service层处理业务。

将处理结果封装成 JSON/XML 返回给前端(RESTful API)或者选择视图进行渲染(传统MVC)。

注解: @RestController(用于API), @Controller(用于MVC), @RequestMapping, @GetMapping, @PostMapping等。

示例 (一个RESTful API Controller):

package com.example.yourapp.controller;
import com.example.yourapp.entity.User;
import com.example.yourapp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController // 表明这个类的所有方法返回的数据直接写入响应体,而不是视图名
@RequestMapping("/api/users") // 父路径
public class UserController {
    @Autowired // 依赖注入,将UserService注入进来
    private UserService userService;
    @GetMapping // 处理 GET /api/users 请求
    public List<User> getAllUsers() {
        return userService.findAllUsers(); // 调用服务层方法
    }
    @GetMapping("/{id}") // 处理 GET /api/users/1 请求
    public User getUserById(@PathVariable Long id) { // @PathVariable 获取URL中的变量
        return userService.findUserById(id);
    }
    @PostMapping // 处理 POST /api/users 请求
    public User createUser(@RequestBody User user) { // @RequestBody 解析请求体中的JSON
        return userService.createUser(user);
    }
}

3. 业务逻辑层 (Service)

  • 位置: com.example.yourapp.service
  • 职责:包含应用的核心业务逻辑和计算规则。
    • •处理事务管理(通常使用 @Transactional注解)。
    • •调用Repository层来获取或持久化数据。
    • •这一层是解耦的关键,Controller 不应该直接访问 Repository。
  • 注解: @Service, @Transactional
  • 示例:
package com.example.yourapp.service;
import com.example.yourapp.entity.User;
import com.example.yourapp.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service // 标记为Spring管理的业务逻辑组件
public class UserService {
    @Autowired
    private UserRepository userRepository;
    // 业务方法:获取所有用户
    public List<User> findAllUsers() {
        return userRepository.findAll(); // 直接调用Repository
    }
    // 业务方法:创建用户,并开启事务
    @Transactional // 此方法会在一个数据库事务中执行
    public User createUser(User user) {
        // 这里可以添加业务逻辑,例如:检查用户名是否已存在
        if (userRepository.existsByUsername(user.getUsername())) {
            throw new RuntimeException("Username already exists!");
        }
        // ... 其他业务逻辑,如密码加密等
        return userRepository.save(user); // 保存到数据库
    }

    public User findUserById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("User not found"));
    }
}

4. 数据访问层 (Repository / Dao)

  • 位置: com.example.yourapp.repository
  • 职责:直接与数据库交互,执行CRUD(增删改查)操作。
    • •这是最数据库相关的部分。
    • •通常通过继承 Spring Data JPA 的接口来获得大部分通用方法,无需编写实现。
  • 注解: @Repository(可省略,因为JpaRepository已经包含了)。
  • 示例:
package com.example.yourapp.repository;
import com.example.yourapp.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository // 标记为数据访问组件
public interface UserRepository extends JpaRepository<User, Long> {
    // JpaRepository<User, Long> 提供了 save(), findById(), findAll(), deleteById() 等基本方法
    // 根据方法名自动生成查询(Spring Data JPA 的强大功能)
    Optional<User> findByUsername(String username);
    Boolean existsByUsername(String username);

    // 你也可以使用 @Query 注解来自定义JPQL或原生SQL查询
    // @Query("SELECT u FROM User u WHERE u.email = :email")
    // Optional<User> findByEmailAddress(@Param("email") String email);
}

5. 实体类 (Entity / Model)

  • 位置: com.example.yourapp.entitymodel

  • 职责:

    映射数据库中的表结构。每个实体类实例代表数据库中的一行记录。

    这是高度数据库相关的模型定义。

  • 注解: @Entity, @Table, @Id, @GeneratedValue, @Column等 (JPA注解)。

  • 示例:

package com.example.yourapp.entity;
import javax.persistence.*;
@Entity // 告诉JPA这是一个实体类,将会被映射到数据库表
@Table(name = "users") // 指定映射的表名,如果类名和表名一致可省略
public class User {
    @Id // 标记为主键
    @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增策略
    private Long id;
    @Column(nullable = false, unique = true, length = 50) // 映射字段,非空,唯一,长度50
    private String username;

    @Column(nullable = false)
    private String password;

    @Column(name = "email_address") // 映射到数据库中的 email_address 列
    private String email;

    // 必须有无参构造函数
    public User() {
    }

    // 通常会有全参构造函数、Getter和Setter方法
    // ... (通常使用Lombok的 @Data 注解来省略手写)
}

6. 资源配置文件

  • 位置: src/main/resources/

  • 职责:

    application.properties/ application.yml: 核心配置文件,配置数据库连接、服务器端口、日志级别、第三方密钥等。

    static/: 存放静态资源,如 .css, .js, 图片等。访问时无需经过Controller,如 http://localhost:8080/css/style.css

    templates/: 存放服务器端模板文件,如 .html(由Thymeleaf或Freemarker渲染)。

示例 (application.yml):

# 配置数据源 (数据库相关)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/my_database?useSSL=false&serverTimezone=UTC
    username: root
    password: mypassword
    driver-class-name: com.mysql.cj.jdbc.Driver

  # 配置JPA (数据库相关)
  jpa:
    hibernate:
      ddl-auto: update # 启动时根据实体类自动更新表结构(生产环境慎用)
    show-sql: true # 在控制台显示执行的SQL语句

# 配置服务器
server:
  port: 8080

# 自定义配置
myapp:
  upload-path: /var/uploads/

总结与关系梳理

组件/层 包位置 核心职责 相关技术注解
启动类 基包根目录 应用入口,启动Spring容器 @SpringBootApplication
控制层 .controller 处理HTTP请求/响应,桥梁 @RestController, @GetMapping
业务逻辑层 .service 实现核心业务逻辑,事务管理 @Service, @Transactional
数据访问层 .repository 与数据库交互,CRUD操作 @Repository(常省略), JPA接口
实体类 .entity 映射数据库表,数据模型 @Entity, @Id, @Column
配置文件 resources/ 配置应用参数,数据库连接等 application.properties/yml

数据流

  1. 1.请求进入:客户端 -> Controller
  2. 2.逻辑处理Controller-> Service
  3. 3.数据存取Service-> Repository-> 数据库
  4. 4.响应返回:数据库 -> Repository-> Service-> Controller-> 客户端

这种分层架构确保了代码的高内聚、低耦合,每一层职责单一,便于开发、测试和维护


文章作者: 读序
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 读序 !
  目录