You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript联合返回类型的Java替代方案及实现问题咨询

解决Java实现neverthrow Result时Err.andThen的类型兼容问题

核心问题分析

TypeScript的联合类型E | F在Java中没有直接等价物,且Java泛型是不变的——Err<T, E>无法直接赋值给Result<U, E | F>(甚至没有E | F这种类型)。而neverthrow中Err的andThen逻辑是直接返回自身,这就需要在Java中通过泛型约束和安全的类型转换来适配。

可行解决方案

1. 重构Result接口与Err类

首先,Err状态下不会访问value,因此可以去掉Err类中不必要的T泛型,简化类型结构:

import java.util.function.Function;

// 定义基础Result接口
public interface Result<T, E> {
    // 引入泛型G作为返回结果的错误超类型,兼容原错误E和新错误F
    <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn);
}

// Ok类:持有有效结果,正常执行andThen逻辑
public class Ok<T, E> implements Result<T, E> {
    private final T value;

    public Ok(T value) {
        this.value = value;
    }

    @Override
    public <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn) {
        return fn.apply(value);
    }
}

// Err类:去掉T泛型,因为Err状态下不会使用value
public class Err<E> implements Result<Object, E> {
    private final E error;

    public Err(E error) {
        this.error = error;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <U, G> Result<U, G> andThen(Function<Object, Result<U, ? extends G>> fn) {
        // 安全转换:Err状态下不会触发fn,value类型不影响;E必然是G的子类型(编译器自动推断G为E和F的共同超类型)
        return (Result<U, G>) this;
    }
}

2. 类型适配逻辑说明

  • 泛型参数G:编译器会自动推断G为原错误类型E和fn返回的错误类型F的最小共同超类型(比如E=IOException、F=SQLException时,G=Exception)。
  • Err的类型转换:由于Err状态下不会执行andThen传入的函数,返回的Err实例的value类型(Object)不会被访问,因此强制转换为Result<U, G>是安全的。
  • 兼容性保证:Ok类执行fn后返回的Result<U, F>,因F extends G,自然符合Result<U, G>的类型要求;Err类转换后的实例也符合该类型,完美匹配方法返回值。

3. 使用示例

public class Main {
    public static void main(String[] args) {
        // Ok状态:执行andThen转换类型
        Result<String, IOException> okResult = new Ok<>("test");
        Result<Integer, Exception> intResult = okResult.andThen(s -> 
            new Ok<>(s.length())
        );

        // Err状态:直接返回自身,类型自动适配
        Result<String, IOException> errResult = new Err<>(new IOException("error"));
        Result<Integer, Exception> errIntResult = errResult.andThen(s -> 
            new Ok<>(s.length())
        );
    }
}

替代方案:保留Err的T泛型

如果需要保留Err的T泛型(比如某些场景下需要访问Err的value),可以通过通配符和类型转换实现:

public class Err<T, E> implements Result<T, E> {
    private final T value;
    private final E error;

    public Err(T value, E error) {
        this.value = value;
        this.error = error;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn) {
        return (Result<U, G>) this;
    }
}

这种方式本质和之前一致,只是保留了T泛型,转换逻辑同样安全——因为Err状态下不会触发fn,也不会被当作Ok状态访问U类型的value。

内容的提问来源于stack exchange,提问作者Dmitry Zlykh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:54:52