Files

88 lines
4.4 KiB
Java
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Java 基础对照示例(不依赖 Spring,只用 JDK):record、接口 + 构造器注入、Optional、Stream、异常、并发
// 运行(JDK 21+):java OrderDemo.java —— 单文件源码直接运行,不需要先 javac
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class OrderDemo {
// record:不可变数据类,自动生成构造器、getter、equals/hashCode/toString(类似 Go struct / Python dataclass(frozen))
record Order(String id, String tenant, String status, BigDecimal amount) {}
// 接口 + 实现:Spring 中会用 @Repository 标注,由容器创建并注入
interface OrderRepository {
Optional<Order> findById(String id);
List<Order> findByTenant(String tenant);
}
static class InMemoryOrderRepository implements OrderRepository {
private final Map<String, Order> data = new ConcurrentHashMap<>();
InMemoryOrderRepository(List<Order> seed) { seed.forEach(o -> data.put(o.id(), o)); }
public Optional<Order> findById(String id) { return Optional.ofNullable(data.get(id)); }
public List<Order> findByTenant(String tenant) {
return data.values().stream().filter(o -> o.tenant().equals(tenant)).toList();
}
}
static class NotFoundException extends RuntimeException {
NotFoundException(String msg) { super(msg); }
}
// 构造器注入:Spring 推荐的方式(@Service),依赖是 final 的,测试时可以直接传入假实现
static class OrderService {
private final OrderRepository repo;
OrderService(OrderRepository repo) { this.repo = repo; }
Order get(String tenant, String id) {
return repo.findById(id)
.filter(o -> o.tenant().equals(tenant)) // 租户隔离:别的租户的订单当作不存在
.orElseThrow(() -> new NotFoundException("订单不存在: " + id));
}
Map<String, BigDecimal> sumByStatus(String tenant) { // Stream 分组汇总;金额用 BigDecimal,不用 double
return repo.findByTenant(tenant).stream()
.collect(Collectors.groupingBy(Order::status,
Collectors.reducing(BigDecimal.ZERO, Order::amount, BigDecimal::add)));
}
}
public static void main(String[] args) throws Exception {
var repo = new InMemoryOrderRepository(List.of(
new Order("A001", "t1", "paid", new BigDecimal("19.90")),
new Order("A002", "t1", "paid", new BigDecimal("0.10")),
new Order("A003", "t1", "refunded", new BigDecimal("5.00")),
new Order("B001", "t2", "paid", new BigDecimal("99.00"))));
var service = new OrderService(repo);
check(service.get("t1", "A001").amount().equals(new BigDecimal("19.90")), "查询订单");
try {
service.get("t1", "B001");
check(false, "跨租户应当查不到");
} catch (NotFoundException e) {
System.out.println("跨租户查询被拒绝: " + e.getMessage());
}
var sums = service.sumByStatus("t1");
check(sums.get("paid").equals(new BigDecimal("20.00")), "BigDecimal 精确求和");
System.out.println("t1 按状态汇总: " + new java.util.TreeMap<>(sums));
System.out.println("用 double 计算金额的问题: 0.1 + 0.2 = " + (0.1 + 0.2));
// 并发:虚拟线程(JDK 21 正式特性)+ 原子计数,类比 Go 的 goroutine
var counter = new AtomicInteger();
try (ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 1000; i++) pool.submit(counter::incrementAndGet);
} // try-with-resources:等待全部任务完成
check(counter.get() == 1000, "虚拟线程并发计数");
System.out.println("1000 个虚拟线程计数结果: " + counter.get());
System.out.println("全部检查通过");
}
static void check(boolean ok, String name) {
if (!ok) throw new AssertionError("检查失败: " + name);
}
}