在Java中创建ImmutablePairs的Union类型的最佳方法

huangapple go评论111阅读模式
英文:

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 ImmutablePairs?

答案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 {
&lt;T&gt; T get(Function&lt;String,T&gt; stringFunc, Function&lt;Double,T&gt; doubleFunc);
class StringVersion implements StringOrDouble {
private final String string;
public StringVersion(String string) {
this.string = string;
}
@Override
public &lt;T&gt; T get(Function&lt;String, T&gt; stringFunc, Function&lt;Double, T&gt; doubleFunc) {
return stringFunc.apply(string);
}
}
class DoubleVersion implements StringOrDouble {
private final Double doubleValue;
public DoubleVersion(Double doubleValue) {
this.doubleValue = doubleValue;
}
@Override
public &lt;T&gt; T get(Function&lt;String, T&gt; stringFunc, Function&lt;Double, T&gt; 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(&quot;hello&quot;),ofDouble(101.0)};
for (StringOrDouble v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}

And then use:

List&lt;ImmutablePair&lt;Integer, StringOrDouble&gt;&gt; params;

Or a generic version:

import java.util.List;
import java.util.function.Function;
public interface Union&lt;A, B&gt; {
&lt;T&gt; T get(Function&lt;A, T&gt; aFunc, Function&lt;B, T&gt; bFunc);
class AVersion&lt;A, B&gt; implements Union&lt;A, B&gt; {
private final A a;
public AVersion(A a) {
this.a = a;
}
@Override
public &lt;T&gt; T get(Function&lt;A, T&gt; aFunc, Function&lt;B, T&gt; bFunc) {
return aFunc.apply(a);
}
}
class BVersion&lt;A, B&gt; implements Union&lt;A, B&gt; {
private final B b;
public BVersion(B b) {
this.b = b;
}
@Override
public &lt;T&gt; T get(Function&lt;A, T&gt; aFunc, Function&lt;B, T&gt; bFunc) {
return bFunc.apply(b);
}
}
static &lt;A, B&gt; Union&lt;A, B&gt; ofA(A a) {
return new AVersion&lt;&gt;(a);
}
static &lt;A, B&gt; Union&lt;A, B&gt; ofB(B b) {
return new BVersion&lt;&gt;(b);
}
public static void main(String[] args) {
List&lt;Union&lt;String, Double&gt;&gt; vs = List.of(ofA(&quot;hello&quot;), ofB(101.0));
for (Union&lt;String, Double&gt; v : vs) {
System.out.println(v.get(String::toUpperCase, Double::toHexString));
}
}
}

We can also add a method to Union:

    default void use(Consumer&lt;A&gt; aConsumer, Consumer&lt;B&gt; bConsumer) {
get(a -&gt; {aConsumer.accept(a); return null;}, b -&gt; {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&lt;String, Double&gt; u = ofA(&quot;a string&quot;);
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&lt;A, B&gt; {
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 &lt;A, B&gt; Union&lt;A, B&gt; ofA(A a) {
return new Union&lt;A, B&gt;(Objects.requireNonNull(a), null);
}
public static &lt;A, B&gt; Union&lt;A, B&gt; ofB(B b) {
return new Union&lt;A, B&gt;(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&lt;String, Double&gt; union = Union.ofA(&quot;bla&quot;);
if(union.isA()) {
System.out.println(union.getA());
}
if(union.isB()) {
System.out.println(union.getB());
}

huangapple
  • 本文由 发表于 2023年6月19日 12:30:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76503613.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定