英文:
Best way to create a Union type for ImmutablePairs in Java
问题
在我需要改进的Java程序中,我有一个数据结构:
List<ImmutablePair<Integer, String>> params;
使用org.apache.commons.lang3.tuple
中的ImmutablePair
。
接下来,我希望String参数能够容纳要么是一个String
或一个Double
。为此,我想创建类似于这两种基本类型的联合或Sum类型。
我如何在Java中为ImmutablePair
的列表定义这个?
英文:
In a Java program that I need to enhance I have a data structure
List<ImmutablePair<Integer, String>> params;
using ImmutablePair
from org.apache.commons.lang3.tuple
.
Going forward the String parameter needs to be able to hold either a String
or a Double
. For this I would like to create something like a union or Sum type of the two basic types.
How do I define this in Java for a list of ImmutablePair
s?
答案1
得分: 2
不清楚您的问题与ImmutablePair
有何关系。
我会这样做:
import java.util.function.Function;
public interface StringOrDouble {
<T> T get(Function<String, T> stringFunc, Function<Double, T> doubleFunc);
class StringVersion implements StringOrDouble {
private final String string;
public StringVersion(String string) {
this.string = string;
}
@Override
public <T> T get(Function<String, T> stringFunc, Function<Double, T> doubleFunc) {
return stringFunc.apply(string);
}
}
class DoubleVersion implements StringOrDouble {
private final Double doubleValue;
public DoubleVersion(Double doubleValue) {
this.doubleValue = doubleValue;
}
@Override
public <T> T get(Function<String, T> stringFunc, Function<Double, T> doubleFunc) {
return doubleFunc.apply(doubleValue);
}
}
static StringOrDouble ofString(String string) {
return new StringVersion(string);
}
static StringOrDouble ofDouble(Double doubleValue) {
return new DoubleVersion(doubleValue);
}
public static void main(String[] args) {
StringOrDouble[] vs = {ofString("hello"), ofDouble(101.0)};
for (StringOrDouble v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}
然后使用:
List<ImmutablePair<Integer, StringOrDouble>> params;
或者泛型版本:
import java.util.List;
import java.util.function.Function;
public interface Union<A, B> {
<T> T get(Function<A, T> aFunc, Function<B, T> bFunc);
class AVersion<A, B> implements Union<A, B> {
private final A a;
public AVersion(A a) {
this.a = a;
}
@Override
public <T> T get(Function<A, T> aFunc, Function<B, T> bFunc) {
return aFunc.apply(a);
}
}
class BVersion<A, B> implements Union<A, B> {
private final B b;
public BVersion(B b) {
this.b = b;
}
@Override
public <T> T get(Function<A, T> aFunc, Function<B, T> bFunc) {
return bFunc.apply(b);
}
}
static <A, B> Union<A, B> ofA(A a) {
return new AVersion<>(a);
}
static <A, B> Union<A, B> ofB(B b) {
return new BVersion<>(b);
}
public static void main(String[] args) {
List<Union<String, Double>> vs = List.of(ofA("hello"), ofB(101.0));
for (Union<String, Double> v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}
我们还可以向Union
添加一个方法:
default void use(Consumer<A> aConsumer, Consumer<B> bConsumer) {
get(a -> {aConsumer.accept(a); return null;}, b -> {bConsumer.accept(b); return null;});
}
这允许我们传递void方法,因此如果我们有一个类似于:
class Foo {
private String s;
private double d;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
}
我们可以这样做:
Union<String, Double> u = ofA("a string");
Foo f = new Foo();
u.use(f::setS, f::setD);
然后将调用适当的setter方法。
英文:
I'm not clear what your question has to do with ImmutablePair
.
I would just do something like this:
import java.util.function.Function;
public interface StringOrDouble {
<T> T get(Function<String,T> stringFunc, Function<Double,T> doubleFunc);
class StringVersion implements StringOrDouble {
private final String string;
public StringVersion(String string) {
this.string = string;
}
@Override
public <T> T get(Function<String, T> stringFunc, Function<Double, T> doubleFunc) {
return stringFunc.apply(string);
}
}
class DoubleVersion implements StringOrDouble {
private final Double doubleValue;
public DoubleVersion(Double doubleValue) {
this.doubleValue = doubleValue;
}
@Override
public <T> T get(Function<String, T> stringFunc, Function<Double, T> doubleFunc) {
return doubleFunc.apply(doubleValue);
}
}
static StringOrDouble ofString(String string) {
return new StringVersion(string);
}
static StringOrDouble ofDouble(Double doubleValue) {
return new DoubleVersion(doubleValue);
}
public static void main(String[] args) {
StringOrDouble[] vs = {ofString("hello"),ofDouble(101.0)};
for (StringOrDouble v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}
And then use:
List<ImmutablePair<Integer, StringOrDouble>> params;
Or a generic version:
import java.util.List;
import java.util.function.Function;
public interface Union<A, B> {
<T> T get(Function<A, T> aFunc, Function<B, T> bFunc);
class AVersion<A, B> implements Union<A, B> {
private final A a;
public AVersion(A a) {
this.a = a;
}
@Override
public <T> T get(Function<A, T> aFunc, Function<B, T> bFunc) {
return aFunc.apply(a);
}
}
class BVersion<A, B> implements Union<A, B> {
private final B b;
public BVersion(B b) {
this.b = b;
}
@Override
public <T> T get(Function<A, T> aFunc, Function<B, T> bFunc) {
return bFunc.apply(b);
}
}
static <A, B> Union<A, B> ofA(A a) {
return new AVersion<>(a);
}
static <A, B> Union<A, B> ofB(B b) {
return new BVersion<>(b);
}
public static void main(String[] args) {
List<Union<String, Double>> vs = List.of(ofA("hello"), ofB(101.0));
for (Union<String, Double> v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}
We can also add a method to Union
:
default void use(Consumer<A> aConsumer, Consumer<B> bConsumer) {
get(a -> {aConsumer.accept(a); return null;}, b -> {bConsumer.accept(b); return null;});
}
Which allows us to pass void methods, so if we have a bean like:
class Foo {
private String s;
private double d;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public double getD() {
return d;
}
public void setD(double d) {
this.d = d;
}
}
we can do:
Union<String, Double> u = ofA("a string");
Foo f = new Foo();
u.use(f::setS, f::setD);
And the appropriate setter will be called.
答案2
得分: 2
以下是翻译好的代码部分:
不太确定我是否正确理解了问题,但实现联合类型的一种非常简单的方法是:
public class Union<A, B> {
private final A a;
private final B b;
private Union(A a, B b) {
this.a = a;
this.b = b;
}
public boolean isA() {
return a != null;
}
public boolean isB() {
return b != null;
}
public A getA() {
if (isA()) {
return a;
}
throw new NoSuchElementException();
}
public B getB() {
if (isB()) {
return b;
}
throw new NoSuchElementException();
}
public static <A, B> Union<A, B> ofA(A a) {
return new Union<A, B>(Objects.requireNonNull(a), null);
}
public static <A, B> Union<A, B> ofB(B b) {
return new Union<A, B>(null, Objects.requireNonNull(b));
}
}
如果不使用泛型,您还可以省略静态的 `of` 方法,而只是使用两个不同的构造函数,但是由于类型擦除的原因,对于泛型来说这不会起作用。
您可以这样调用它:
Union<String, Double> union = Union.ofA("bla");
if (union.isA()) {
System.out.println(union.getA());
}
if (union.isB()) {
System.out.println(union.getB());
}
英文:
Not completely sure if I read the question correctly, but a very easy way to implement a union type would be:
public class Union<A, B> {
private final A a;
private final B b;
private Union(A a, B b) {
this.a = a;
this.b = b;
}
public boolean isA() {
return a != null;
}
public boolean isB() {
return b != null;
}
public A getA() {
if(isA()) {
return a;
}
throw new NoSuchElementException();
}
public B getB() {
if(isB()) {
return b;
}
throw new NoSuchElementException();
}
public static <A, B> Union<A, B> ofA(A a) {
return new Union<A, B>(Objects.requireNonNull(a), null);
}
public static <A, B> Union<A, B> ofB(B b) {
return new Union<A, B>(null, Objects.requireNonNull(b));
}
}
If you don't use generics you could also drop the static of
methods and simply use two different constructors but with generics that won't work because of the type erasure.
You'd call is like this:
Union<String, Double> union = Union.ofA("bla");
if(union.isA()) {
System.out.println(union.getA());
}
if(union.isB()) {
System.out.println(union.getB());
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论