技术拾遗
Created|Updated|Java
|Word Count:189|Reading Time:1mins|Post Views:
Java
Java 8
Lambda
Java 8 Lambdas - A Peek Under the Hood
What does $$ in javac generated name mean?
-
lambda 表达式并不总是持有外部 enclosing object 的引用,如果它不访问任何外部变量,即不持有这样的引用。只要设计一个对比实验,就会发现引用过外部变量的lambda实例才会产生一个 arg 的隐式参数引用。而内部类内部总是含有一个
this$0。 -
lambda表达式是词法作用域的-意思是不产生新的作用域,不产生任何shadowing问题。它可以无缝访问外部作用域的东西,就好像从一个 if block 里访问一个方法里的其他变量一样。但,同样地,不能声明新变量。
Author: magicliang
Copyright Notice: All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Related Articles
2026-10-04
深入 Spring 43:订单应用的六个综合验收场景
一个订单结果需要跨过哪些边界 HTTP 返回 201、数据库出现订单、提交回调执行、异步通知结束,是四个不同的观测结果。请求返回异常时,数据库可能已经提交;客户端超时时,服务器也可能仍在处理。验收把这些结果分别记录,才能判断错误发生在绑定、业务、事务、异步任务还是传输阶段。 综合应用保留此前实验使用的 Spring MVC、JDBC 事务、真实 PostgreSQL、ExecutorService 和 JDK HttpClient。固定 Boot 3.5.6、Framework 6.2.11、JDK 21 与 PostgreSQL 18.0,代码位于 final-lab/。它是围绕同一订单模型的可执行验收应用,没有增加消息中间件、分布式锁或新的编排平台。 独立 JUnit 类 Chapter43Test 通过真实 HTTP 请求和额外数据库连接观察应用,执行正常下单、并发幂等、业务回滚、异步失败、HTTP 超时、关闭六个场景,共 21 条具名断言。数据库写入限定在 spring_final.orders,订单键带本轮 UUID 前缀,清理只删除本次创建的键。 装配固定之后,先确...
2026-09-30
深入 OpenTelemetry 16:Histogram 的桶不是精确分位数
有六个延迟,能求出准确 P95 吗? 固定延迟 [0, 10, 11, 20, 50, 70] 毫秒,count=6、sum=161。若选择显式边界 [10,20,50],采集得到四个桶 [2,2,1,1];仅凭这四个数字,不能还原每条请求的延迟,更无法精确还原 P95。桶累计的是落在哪个范围的次数,而不是原始样本列表。 值 桶(显式边界) 次数 0、10 ≤10 2 11、20 (10,20] 2 50 (20,50] 1 70 >50 1 两种桶的数据对象和源码路径 以下为对 Java SDK 完整 SHA c25c0a0ee0da01ab2f74ba83052d1c249ed57020 的静态阅读。Aggregation.explicitBucketHistogram 可以设置显式边界;默认 histogram 使用该类聚合,默认桶不是本次自定义的 [10,20,50]。DoubleExplicitBucketHistogramAggregator.Handle 维护 count/sum/桶;ExplicitBucketHistogra...
2026-05-17
从 OSGi 到 Jigsaw:Java 模块化、SPI 与类加载器切换
写在前面 Java 的模块化不是从 JPMS 才开始的。很长一段时间里,classpath 像一条足够宽的路,所有 jar 都往上面放,能跑就行。等应用长大,库的版本开始冲突,内部包被外部代码依赖,插件想热更新,SPI 实现又被错误的类加载器发现,这条路才慢慢暴露出它没有边界的问题。 OSGi、JBoss Modules、Jigsaw(JPMS)都试图在 classpath 之上重新划边界,只是三者选择的边界不一样。OSGi 把运行时动态性放在第一位,JBoss Modules 更关心应用服务器内部的静态隔离,JPMS 则把强封装和可靠配置做进了 Java 平台本身。 类加载器切换是这条线上的另一面。Tomcat reload 之后类没卸掉、OSGi 升级 bundle 之后老对象 ClassCastException、JDBC Driver 把整个 webapp 钉在内存里、Spring Boot DevTools 重启后某个 SPI 实现加载了旧版本,这些现象表面上属于不同框架,根子都在 JVM 的类身份模型:一个类不只由全限定名决定,还由定义它的 ClassLoader 决...
2026-10-04
深入 Spring 38:Boot 自动配置的输入、退让与属性绑定
同一个策略类型,为什么加一个 Bean 就变了 订单应用没有声明 OrderPolicy 时,容器里存在一个来源为 auto 的策略。应用新增名叫 customPolicy 的 Bean 后,策略来源变成 user,原先的 orderPolicy 名称也查不到。两者名字不同,Bean definition 覆盖开关保持关闭,应用仍然正常启动。 这个结果说明,自动配置的退让发生在默认定义注册之前。它不能用“后一个同名 Bean 覆盖前一个”解释,也不需要把 Bean 覆盖开关改成允许。判断依据是策略类型与条件评估时已经可见的定义。 Spring Boot 没有重新实现一套依赖注入容器。配置解析、对象创建、后处理器与销毁仍由 Framework 执行。Boot 提供启动流程、配置数据处理、条件化基础设施装配和运行管理。在原生容器里已经定位过的问题,可以继续沿定义来源、候选类型、创建阶段和调用对象追踪;新增的是这些定义为什么被导入。 本篇冻结 Boot 3.5.6,源码提交 23bcd7b4d8969cdef27771f1594b044bb98724a6。独立 boot-lab 使用该...

2026-10-04
设计模式 06:两次独立改需求,为什么都要碰同一服务
一个报价服务算金额、把金额放进内存 Map,再组装给调用方的文本。最初普通客户买 2 件、单价 10.00,得到 20.00 和 CNY 20.00;会员沿用九折得到 18.00。现在分别收到两张变化卡:A 仅在活动开启时把会员改为八折,B 只把展示文本换成 合计(CNY):金额。两张卡来自不同变化来源,金额保存行为不该因为文案变化而改变。旧版 Before 的计算、内存保存和展示全部挤在同一类里。 变化传播不是类数竞赛 Before.quote 的实际顺序是 line.undiscountedTotal() → 按会员九折计算 → saved.put(id, total) → 拼接 CNY 前缀。它接受 promotion 和 detailed 两个开关,却没有处理新要求;对会员开启活动仍保存 18.00,指定详细展示仍返回 CNY 20.00。测试显式断言这两个旧输出,作为可执行的变化压力,不把基线伪装为已满足需求。 拆开的 After 仍只有一个入口,负责按顺序协作: 123BigDecimal total = pricing.total(line, promotion)...

2026-10-04
软件建模38:从领域模型到应用架构——哪些决定还没有作出
明确设备身份、半开租期和取消历史以后,应用仍然可以采用不同的代码组织与部署方式。领域模型没有决定请求从哪里进入、状态存在哪里、消息失败由谁处理,也没有决定需要几个进程。 本篇以冻结的27-v1为参照,执行事务脚本、领域实现和模块门面三种候选,再通过一次真实的本机 HTTP 请求贯穿入口、用例、仓储和发布。实验只在单个 JVM 中运行,逻辑边界与部署边界分别说明。 三个候选保持哪一段行为 共同轨迹包含首次确认、重叠拒绝、相邻确认、取消、晚时钟下重放旧确认、重放旧失败、未知设备、提前量不足,以及复用请求号却改变设备。比较对象包括每一步结果、最终活动数量、完整回执以及历史报价,不能只比较第一条请求返回的字符串。 事务脚本候选把判断集中在 reserve 中:读取设备数据,检查状态与租期,扫描当前占用,计算报价,保存活动记录和回执。它仍复用标识、租期与报价值规则,因此不是故意把所有基础类型退回字符串;主要差别是业务流程的判断顺序集中在一个过程里。 领域候选直接调用27的 RentalApplication,再由真实的设备、Specification、Factory 和 Reservat...
Contents
