我创建了一个Either<A,B>
类来表示和类型。每个实例都包含A
或B
。这由扩展程序Left<A>
和Right<B>
表示。这些类型对用户是隐藏的,仅用于存储对A
或B
的引用,并在Either
中实现抽象方法。这是代码的相关部分:
/**
* A simple SumType implementation. Allows the creation of the Sum Type
* A + B. Every instance of Either is either (haha.. tomatoes, rocks)
* an instance of Left, with a value of type A, or an instance of Right,
* with a value of type B.
* <br><br>
* The types and constructors for Left and Right are not exposed.
* Instead, to construct new instance of Left and Right, the createLeft and createRight
* methods of class Either should be used.
* <br><br>
* The types can be the same, but in that case there isn't much use to using Either.
*
* @param <A> The first type to sum
* @param <B> The second type to sum
* @author Mshnik
*/
public abstract class Either<A, B> {
private final boolean isLeft;
/**
* Constructs a new Either
*
* @param isLeft - true if this is a Left, false if this is a Right
*/
Either(boolean isLeft) {
this.isLeft = isLeft;
}
/** Creates a Either instance of the given A */
public static <A, B> Either<A, B> createLeft(A a) {
return new Left<>(a);
}
/** Creates a Either instance of the given B */
public static <A, B> Either<A, B> createRight(B b) {
return new Right<>(b);
}
/**
* Returns true if this is a Left, false if this is a Right
*/
public boolean isLeft() {
return isLeft;
}
/**
* Returns the value of this Either as an an instance of A.
* If the wrapped value is an instance of B, throws a RuntimeException
*/
public A asLeft() {
if (isLeft())
return ((Left<A,B>)this).getVal();
throw new RuntimeException();
}
/**
* Returns the value of this Either as an an instance of B.
* If the wrapped value is an instance of A, throws a RuntimeException
*/
public B asRight() {
if (!isLeft())
return ((Right<A,B>)this).getVal();
throw new RuntimeException();
}
/**
* Returns the Object stored within this Either.
* Should have a stricter type bound (A or B) when implemented by subclasses.
*/
public abstract Object getVal();
/**
* Returns the type of the Object stored within this Either
*/
public abstract Class<?> getType();
/**
* Two Eithers are equal iff:
* <br>- They are both Left or both Right, the only two direct subclasses
* <br>- The objects they store are equivalent using Objects.equals.
*/
@Override
public boolean equals(Object o) {
if(this == o) return true;
if(o == null) return false;
try {
@SuppressWarnings("unchecked")
Either<A, B> e = (Either<A, B>) o;
return (!(isLeft ^ e.isLeft)) && Objects.equals(getVal(), e.getVal());
} catch (ClassCastException e) {
return false;
}
}
/**
* Hashes an either based on the value it stores.
* This maintains the hash invariant (two equal objects have the same hashcode),
* but is not a perfect hashcode because a Left(a) and Right(a) will have the
* same hashcode but are not equivalent.
*/
@Override
public int hashCode() {
return Objects.hashCode(getVal());
}
}
asLeft()
和asRight()
的预期用途很简单,如下所示:
Either<A,B> e = ....; //Take an either reference
if(e.isLeft()) {
A a = e.asLeft();
//Handle a
} else {
B b = e.asRight();
//Handle b
}
在我的其他项目中非常有用。
现在我的问题 - 我主要使用IntelliJ(并喜欢它),并注意到它有一个功能可以阻止你做可能出错的事情,例如将字符串与==
进行比较。
是否可以为我的Either
课程创建这样的自定义警告,以便在未事先检查Either::asLeft()
的情况下调用Either::isLeft()
会产生警告?假设IntelliJ(社区版)中有自定义警告功能,是否允许这种复杂性?
答案 0 :(得分:0)
是的,理论上可以通过开发插件来实现。但是,在实践中,我建议不要这样做,因为实施此类检查可能需要付出很多努力。但是,您可以通过更改类来使用IntelliJ的空检查,并创建一个标记为getLeftOrNull()
的方法@Nullable
,并返回null而不是抛出异常。然后IntelliJ会警告你,如果你在解除引用之前没有检查null。
另一种选择是使用java 8 Optional并创建一个方法getLeftOptional()
,该方法将包装返回值并强制调用者处理它为空时的情况(即Either
是{{ 1}})。