尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从 new 到 just:聊聊 Java 里那些“造对象”的写法

从 new 到 just:聊聊 Java 里那些“造对象”的写法 一、一切从 new 说起在 Java 里创建一个对象最原始的方式就是newQuery query new Query(上海哪里好玩); Content content new Content(segment);简单、直接、粗暴。只要构造器是public的你就能new出任何东西。但随着项目变大、框架变多你会发现new越来越少见了取而代之的是一堆xxx(...)的方法Query query Query.from(上海哪里好玩); Content content Content.from(segment); MonoString mono Mono.just(hello);这些方法看起来像new用起来也像new但它们到底是什么为什么要用它们这篇就来聊聊这个话题。二、静态工厂方法披着方法皮的“new”Query.from(...)、Content.from(...)、List.of(...)、Map.of(...)、Optional.ofNullable(...)这些都有一个共同的名字静态工厂方法Static Factory Method。它们的特点是static方法直接通过类名调用。返回当前类或相关类的实例。内部通常就是调用new或者做了一些额外的处理。比如Query.from(qText)内部可能就是这样public static Query from(String text) { return new Query(text); }那为什么明明可以new还要绕一层from呢理由一构造器可能是私有的框架作者有时候故意把构造器设为private强制你只能通过工厂方法创建对象。这样做可以控制对象的创建过程。做参数校验。返回缓存对象或子类对象。你写new Query(...)会编译报错但Query.from(...)可以用。理由二语义更清晰new只能表示“创建”而工厂方法可以起不同的名字表达不同的意图Query.from(text); // 从文本创建 Query.from(text, metadata); // 从文本 元数据创建 List.of(a, b); // 从若干元素创建 Map.of(k1, v1); // 从键值对创建 Optional.ofNullable(value); // 从可能为 null 的值创建比new Query(text)更能说明“我是从哪儿来的”。理由三可读性和链式调用ListString list List.of(a, b, c); MapString, Integer map Map.of(a, 1, b, 2);如果换成new ArrayList(Arrays.asList(a, b, c))是不是看起来更累赘三、from 和 of名字不同作用相似在 Java 生态里静态工厂方法常用的名字有几种方法名含义例子from从某个参数转换而来Query.from(text)of从若干参数构造List.of(...)、Map.of(...)valueOf转成某种值Integer.valueOf(123)create创建新实例Document.create()newInstance创建新实例Array.newInstance(...)from强调“来源”of强调“由这些组成”valueOf强调“值的转换”。用哪个看框架作者的喜好。在 LangChain4j 里Query.from(...)、Content.from(...)、TextSegment.from(...)都是这个思路——用一个语义化的静态方法代替new。四、到了 Reactor画风突变前面那些from、of、valueOf本质都还是“造普通对象”。到了 Reactor事情开始变得不一样。MonoString mono Mono.just(hello); FluxString flux Flux.just(a, b, c);这里的Mono.just(...)也是静态工厂方法但它造出来的不是普通数据对象而是响应式流容器。一个MonoString不是一个String而是一个“未来会发出String的异步流”。它有的不是值本身而是“值会来”这个承诺。所以String s hello; // 直接拿着一个字符串 MonoString mono Mono.just(s); // 把字符串装进一个异步容器这两者完全不是一个层次的东西。五、just 和 fromCallable两个方向的工厂在 Reactor 里最常见的两个创建方法是just和fromCallableMono.just(hello); // 值已经有了直接包 Mono.fromCallable(() - doSomething()); // 值还没算等订阅时再算区别在于惰性方法是否惰性能否抛异常场景Mono.just(x)否立即创建不能已有值直接包装Mono.fromCallable(() - ...)是订阅才执行能包装阻塞/可能抛异常的代码just是“我手里有个值包一下”。fromCallable是“我有一段逻辑等一下再算”。这在异步编程里很关键。比如你要执行一个阻塞的数据库查询绝不能用just直接包结果——因为结果还没算出来呢。你得用fromCallable让 Reactor 在订阅时真正去执行MonoUser user Mono.fromCallable(() - userMapper.selectById(1));六、Flux::just —— 从 Mono 到 Flux 的桥梁你会在代码里见到这种写法.flatMapMany(Flux::just)这是方法引用等价于.flatMapMany(output - Flux.just(output))它的意思是把上游MonoString里的那个output转成一个只包含它的FluxString。为什么需要这一步Mono只能发 0 或 1 个元素。方法返回类型是FluxString0 到 N 个。类型不匹配所以要“展开”一下。Flux::just就是把这个Mono展开成Flux的最简方式。七、归纳new 和它的“马甲们”走到这里我们可以给这些“造对象”的写法做一张全家福写法类型层次是否惰性本质new Query(...)业务对象否原生创建Query.from(...)业务对象否静态工厂通常就是newList.of(...)/Map.of(...)集合否静态工厂创建不可变集合Mono.just(x)响应式流否包装已有值Mono.fromCallable(...)响应式流是延迟执行最核心的一句话from、of、valueOf是“造普通数据对象”的静态工厂just、fromCallable是“造响应式流”的静态工厂。它们都是“代替new”但造出来的东西不是一个层次的东西。Query.from(...)≈new Query(...)Mono.just(x)≈new MonoWrapper(x)区别是前者造的是一个具体的 Java 对象后者造的是一个“流”。八、为什么框架要用静态工厂总结一下静态工厂方法的几大好处控制创建过程构造器可以是私有的外部只能通过工厂方法创建。语义清晰from、of、valueOf比new更能表达意图。可缓存工厂方法可以返回缓存对象比如Boolean.TRUE、Integer.valueOf(1)。可返回子类工厂方法可以返回当前类的子类更灵活。可扩展以后加逻辑不用改调用方代码。API 稳定隐藏构造细节方便以后演进。这也是《Effective Java》里第一条建议“考虑用静态工厂方法代替构造器”。九、结语写代码的时候你会经常遇到这三个关键字new、from、just。当你手里已经有值只想创建一个对象时用new或from。当你手里有个值想把它变成流时用just。当你手里有段逻辑想延迟执行时用fromCallable。它们看起来长得像用起来感觉也差不多但背后的层次完全不同new造的是“数据”just造的是“数据流动的方式”。
返回列表