phase 5 part 4: java-spring awareness, k8s basics with validated manifests, run_examples supports single-file Java

This commit is contained in:
Shikui Wang committed 2026-10-23 16:42:04 +08:00
1 parent 075872e31e
commit f695bbd7cc
18 files changed
+1192 -23

No files matched your search

@@ -0,0 +1,87 @@
// 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);
}
}