在 Java 8 中是否有 Scala 的任何一个等价物? [英] Is there an equivalent of Scala's Either in Java 8?
问题描述
就像 Java 8 中的 java.util.Optional<T>
是(有点)等价于 Scala 的 Option[T]
类型,是否有等价于 Scala 的 <代码>要么[L,R]代码>?
没有Either
类型是Java 8,所以需要自己创建一个或者使用一些第三方库.>
您可以使用新的 Optional
类型构建这样的功能(但请阅读本答案的末尾):
final class 要么{公共静态<L,R>左(L值){返回新的任一<>(Optional.of(value), Optional.empty());}公共静态<L,R>右(R值){返回新的任一<>(Optional.empty(), Optional.of(value));}private final 可选的剩下;private final Optional<R>对;私人要么(可选 l,可选 r){左=l;右=r;}公共 <T>T图(功能lFunc,功能rFunc){map(lFunc).orElseGet(()->right.map(rFunc).get());}公共 <T>或者 <T,R>mapLeft(Function super L, ? extends T> lFunc){返回新的(left.map(lFunc),right);}公共 <T>mapRight(Function super R, ? extends T> rFunc){返回新的(左,右.map(rFunc));}public void apply(Consumer super L> lFunc, Consumer super R> rFunc){left.ifPresent(lFunc);right.ifPresent(rFunc);}}
示例用例:
new Random().ints(20, 0, 2).mapToObj(i -> (Either)(i==0?要么.left(左值(字符串)"):要么.right(42))).forEach(either->either.apply(left ->{ System.out.println("接收到的左值:"+left.substring(11));},right->{ System.out.println("收到正确的值:0x"+Integer.toHexString(right));}));
回想起来,基于 Optional
的解决方案更像是一个学术示例,而不是推荐的方法.一个问题是将 null
处理为空",这与要么"的含义相矛盾.
下面的代码显示了一个 Either
,它认为 null
是一个可能的值,所以它是严格的要么",左或右,即使值是 null代码>:
抽象类Either{公共静态<L,R>左(L值){返回新的Either<L,R>(){@Override public <T>T map(Function super L, ? extends T> lFunc,功能rFunc) {返回 lFunc.apply(value);}};}公共静态<L,R>右(R值){返回新的Either<L,R>(){@Override public <T>T map(Function super L, ? extends T> lFunc,功能rFunc) {返回 rFunc.apply(value);}};}私有的(){}公共摘要 <T>T图(功能lFunc,FunctionrFunc);公共 <T>或者 <T,R>mapLeft(Function super L, ? extends T> lFunc) {返回 this.}公共 <T>mapRight(Function super R, ? extends T> lFunc) {返回这个.}公共无效申请(消费者 lFunc,消费者 rFunc){地图(消费(lFunc),消费(rFunc));}私人 <T>函数消费(消费者 c){返回 t ->{ c.accept(t);返回空;};}}
只需在两个工厂方法的开头插入一个 Objects.requireNonNull(value)
,就可以轻松地将其更改为严格拒绝 null
.同样,添加对空值的支持也是可以想象的.
Just like java.util.Optional<T>
in Java 8 is (somewhat) equivalent to Scala's Option[T]
type, is there an equivalent to Scala's Either[L, R]
?
There is no Either
type is Java 8, so you need to create one yourself or use some third-party library.
You may build such a feature using the new Optional
type (but read to the end of this answer):
final class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<>(Optional.of(value), Optional.empty());
}
public static <L,R> Either<L,R> right(R value) {
return new Either<>(Optional.empty(), Optional.of(value));
}
private final Optional<L> left;
private final Optional<R> right;
private Either(Optional<L> l, Optional<R> r) {
left=l;
right=r;
}
public <T> T map(
Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc)
{
return left.<T>map(lFunc).orElseGet(()->right.map(rFunc).get());
}
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc)
{
return new Either<>(left.map(lFunc),right);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> rFunc)
{
return new Either<>(left, right.map(rFunc));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc)
{
left.ifPresent(lFunc);
right.ifPresent(rFunc);
}
}
Example use case:
new Random().ints(20, 0, 2).mapToObj(i -> (Either<String,Integer>)(i==0?
Either.left("left value (String)"):
Either.right(42)))
.forEach(either->either.apply(
left ->{ System.out.println("received left value: "+left.substring(11));},
right->{ System.out.println("received right value: 0x"+Integer.toHexString(right));}
));
In retrospective, the Optional
based solution is more like an academic example, but not a recommended approach. One problem is the treatment of null
as "empty" which contradicts the meaning of "either".
The following code shows an Either
that considers null
a possible value, so it’s strictly "either", left or right, even if the value is null
:
abstract class Either<L,R>
{
public static <L,R> Either<L,R> left(L value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return lFunc.apply(value);
}
};
}
public static <L,R> Either<L,R> right(R value) {
return new Either<L,R>() {
@Override public <T> T map(Function<? super L, ? extends T> lFunc,
Function<? super R, ? extends T> rFunc) {
return rFunc.apply(value);
}
};
}
private Either() {}
public abstract <T> T map(
Function<? super L, ? extends T> lFunc, Function<? super R, ? extends T> rFunc);
public <T> Either<T,R> mapLeft(Function<? super L, ? extends T> lFunc) {
return this.<Either<T,R>>map(t -> left(lFunc.apply(t)), t -> (Either<T,R>)this);
}
public <T> Either<L,T> mapRight(Function<? super R, ? extends T> lFunc) {
return this.<Either<L,T>>map(t -> (Either<L,T>)this, t -> right(lFunc.apply(t)));
}
public void apply(Consumer<? super L> lFunc, Consumer<? super R> rFunc) {
map(consume(lFunc), consume(rFunc));
}
private <T> Function<T,Void> consume(Consumer<T> c) {
return t -> { c.accept(t); return null; };
}
}
It’s easy to change that to a strict rejection of null
by simply inserting an Objects.requireNonNull(value)
at the beginning of both factory methods. Likewise, adding support for an empty either would be imaginable.
这篇关于在 Java 8 中是否有 Scala 的任何一个等价物?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!