Java N 元组实现

发布于 2024-09-17 16:39:48 字数 2452 浏览 5 评论 0原文

我刚刚制作了一个类型安全的 Java n 元组。
我正在使用一些非常规方法来实现类型安全(我只是为了好玩而这样做)。

有人可以提供一些改进建议或一些可能的缺陷吗?

public class Tuple {
    private Object[] arr;
    private int size;
    private static boolean TypeLock = false;
    private static Object[] lastTuple = {1,1,1}; //default tuple type

    private Tuple(Object ... c) {
        // TODO Auto-generated constructor stub
        size=c.length;
        arr=c;
        if(TypeLock)
        {
            if(c.length == lastTuple.length)
                for(int i = 0; i<c.length; i++)
                {
                    if(c[i].getClass() == lastTuple[i].getClass())
                        continue;
                    else
                        throw new RuntimeException("Type Locked");
                }
            else
                throw new RuntimeException("Type Locked");
        }

        lastTuple = this.arr;
    }

    public static void setTypeLock(boolean typeLock) {
        TypeLock = typeLock;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if (this == obj)
            return true;

        Tuple p = (Tuple)obj;

        for (int i = 0; i < size; i++)
        {
            if (p.arr[i].getClass() == this.arr[i].getClass())
            {
                if (!this.arr[i].equals(p.arr[i]))
                    return false;
            }
            else
                return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        int res = 17;
        for(int i = 0; i < size; i++)
            res = res*37+arr[i].hashCode();

        return res;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return Arrays.toString(arr);
    }

    public static void main(String[] args) {
        HashMap<Tuple,String> birthDay = new HashMap<Tuple,String>();
        Tuple p = new Tuple(1,2,1986);
        Tuple.setTypeLock(true);
        Tuple p2 = new Tuple(2,10,2009);
        Tuple p3 = new Tuple(1,2,2010);
        Tuple p4 = new Tuple(1,2,2010);
        birthDay.put(p,"Kevin");
        birthDay.put(p2,"Smith");
        birthDay.put(p3,"Sam");
        birthDay.put(p4, "Jack");
        System.out.println(birthDay);
        System.out.println(birthDay.get(new Tuple(1,2,1986)));
        birthDay.put(new Tuple(1,2,""),"");
    }
}

I just made a Java n-tuple which is type-safe.
I'm using some unconventional methods to achieve type-safety (I just made it for fun).

Can someone can give some input on improving it or some possible flaws.

public class Tuple {
    private Object[] arr;
    private int size;
    private static boolean TypeLock = false;
    private static Object[] lastTuple = {1,1,1}; //default tuple type

    private Tuple(Object ... c) {
        // TODO Auto-generated constructor stub
        size=c.length;
        arr=c;
        if(TypeLock)
        {
            if(c.length == lastTuple.length)
                for(int i = 0; i<c.length; i++)
                {
                    if(c[i].getClass() == lastTuple[i].getClass())
                        continue;
                    else
                        throw new RuntimeException("Type Locked");
                }
            else
                throw new RuntimeException("Type Locked");
        }

        lastTuple = this.arr;
    }

    public static void setTypeLock(boolean typeLock) {
        TypeLock = typeLock;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if (this == obj)
            return true;

        Tuple p = (Tuple)obj;

        for (int i = 0; i < size; i++)
        {
            if (p.arr[i].getClass() == this.arr[i].getClass())
            {
                if (!this.arr[i].equals(p.arr[i]))
                    return false;
            }
            else
                return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        int res = 17;
        for(int i = 0; i < size; i++)
            res = res*37+arr[i].hashCode();

        return res;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return Arrays.toString(arr);
    }

    public static void main(String[] args) {
        HashMap<Tuple,String> birthDay = new HashMap<Tuple,String>();
        Tuple p = new Tuple(1,2,1986);
        Tuple.setTypeLock(true);
        Tuple p2 = new Tuple(2,10,2009);
        Tuple p3 = new Tuple(1,2,2010);
        Tuple p4 = new Tuple(1,2,2010);
        birthDay.put(p,"Kevin");
        birthDay.put(p2,"Smith");
        birthDay.put(p3,"Sam");
        birthDay.put(p4, "Jack");
        System.out.println(birthDay);
        System.out.println(birthDay.get(new Tuple(1,2,1986)));
        birthDay.put(new Tuple(1,2,""),"");
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

-柠檬树下少年和吉他 2024-09-24 16:39:48

感谢边做边学。以下是改进的“机会”建议:

  1. 只有一种元组可以存在(一旦设置了类型锁)。这会损害想要使用多种类型元组的程序的可重用性和可扩展性,除非您采用剪切粘贴重用(BirthdayTuple、DimensionsTuple、StreetAddressTuple,...)。考虑一个 TupleFactory 类,它接受目标类型并创建一个元组构建器对象来生成元组。

  2. “null”作为元组中的值的有效性没有记录。我认为在设置Typelock之前,允许null;但是设置 Typelock 后,代码将生成 NullPointerException - 这是不一致的。如果不允许,构造函数应该捕获它并禁止它(无论类型锁如何)。如果它们被允许,那么整个代码(构造函数、等于、哈希码等)需要修改以允许它。

  3. 决定元组是否旨在成为不可变值对象。基于它缺乏 setter 方法,我猜是这样的。如果是这样,那么请小心“采用”传入的数组 - lastTuple=this.arr。即使它是一个 var arg 构造函数,也可以直接使用数组调用该构造函数。该类采用该数组(保留对其的引用),并且数组中的值随后可以在类外部更改。我会做一个数组的浅拷贝,但也会记录具有非不可变值的元组的潜在问题(可以在元组外部更改)。

  4. 您的 equals 方法缺少 null 检查(if (obj == null) return false)和类检查(obj instanceof Tuple > 或 this.getClass().equals(object.getClass()))。 equals 习惯用法已有详细记录。

  5. 除了通过 toString 之外,没有其他方法可以查看元组的值。这保护了 的值和整体不变性,但我认为它限制了类的有用性。

  6. 虽然我意识到这只是一个例子,但我不希望将此类用于生日/日期之类的事情。在具有固定对象类型的解决方案领域中,真实的类(如日期)要好得多。我想这个类在元组是第一类对象的特定领域很有用。

编辑
一直在想这个。这是我对一些代码的看法(关于 github + 测试):

===
Tuple.java
===
package com.stackoverflow.tuple;

/**
 * Tuple are immutable objects.  Tuples should contain only immutable objects or
 * objects that won't be modified while part of a tuple.
 */
public interface Tuple {

    public TupleType getType();
    public int size();
    public <T> T getNthValue(int i);

}


===
TupleType.java
===
package com.stackoverflow.tuple;

/**
 * Represents a type of tuple.  Used to define a type of tuple and then
 * create tuples of that type.
 */
public interface TupleType {

    public int size();

    public Class<?> getNthType(int i);

    /**
     * Tuple are immutable objects.  Tuples should contain only immutable objects or
     * objects that won't be modified while part of a tuple.
     *
     * @param values
     * @return Tuple with the given values
     * @throws IllegalArgumentException if the wrong # of arguments or incompatible tuple values are provided
     */
    public Tuple createTuple(Object... values);

    public class DefaultFactory {
        public static TupleType create(final Class<?>... types) {
            return new TupleTypeImpl(types);
        }
    }

}


===
TupleImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

import java.util.Arrays;

class TupleImpl implements Tuple {

    private final TupleType type;
    private final Object[] values;

    TupleImpl(TupleType type, Object[] values) {
        this.type = type;
        if (values == null || values.length == 0) {
            this.values = new Object[0];
        } else {
            this.values = new Object[values.length];
            System.arraycopy(values, 0, this.values, 0, values.length);
        }
    }

    @Override
    public TupleType getType() {
        return type;
    }

    @Override
    public int size() {
        return values.length;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getNthValue(int i) {
        return (T) values[i];
    }

    @Override
    public boolean equals(Object object) {
        if (object == null)   return false;
        if (this == object)   return true;

        if (! (object instanceof Tuple))   return false;

        final Tuple other = (Tuple) object;
        if (other.size() != size())   return false;

        final int size = size();
        for (int i = 0; i < size; i++) {
            final Object thisNthValue = getNthValue(i);
            final Object otherNthValue = other.getNthValue(i);
            if ((thisNthValue == null && otherNthValue != null) ||
                    (thisNthValue != null && ! thisNthValue.equals(otherNthValue))) {
                return false;
            }
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 17;
        for (Object value : values) {
            if (value != null) {
                hash = hash * 37 + value.hashCode();
            }
        }
        return hash;
    }

    @Override
    public String toString() {
        return Arrays.toString(values);
    }
}


===
TupleTypeImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

class TupleTypeImpl implements TupleType {

    final Class<?>[] types;

    TupleTypeImpl(Class<?>[] types) {
        this.types = (types != null ? types : new Class<?>[0]);
    }

    public int size() {
        return types.length;
    }

    //WRONG
    //public <T> Class<T> getNthType(int i)

    //RIGHT - thanks Emil
    public Class<?> getNthType(int i) {
        return types[i];
    }

    public Tuple createTuple(Object... values) {
        if ((values == null && types.length == 0) ||
                (values != null && values.length != types.length)) {
            throw new IllegalArgumentException(
                    "Expected "+types.length+" values, not "+
                    (values == null ? "(null)" : values.length) + " values");
        }

        if (values != null) {
            for (int i = 0; i < types.length; i++) {
                final Class<?> nthType = types[i];
                final Object nthValue = values[i];
                if (nthValue != null && ! nthType.isAssignableFrom(nthValue.getClass())) {
                    throw new IllegalArgumentException(
                            "Expected value #"+i+" ('"+
                            nthValue+"') of new Tuple to be "+
                            nthType+", not " +
                            (nthValue != null ? nthValue.getClass() : "(null type)"));
                }
            }
        }

        return new TupleImpl(this, values);
    }
}


===
TupleExample.java
===
package com.stackoverflow.tupleexample;

import com.stackoverflow.tuple.Tuple;
import com.stackoverflow.tuple.TupleType;

public class TupleExample {

    public static void main(String[] args) {

        // This code probably should be part of a suite of unit tests
        // instead of part of this a sample program

        final TupleType tripletTupleType =
            TupleType.DefaultFactory.create(
                    Number.class,
                    String.class,
                    Character.class);

        final Tuple t1 = tripletTupleType.createTuple(1, "one", 'a');
        final Tuple t2 = tripletTupleType.createTuple(2l, "two", 'b');
        final Tuple t3 = tripletTupleType.createTuple(3f, "three", 'c');
        final Tuple tnull = tripletTupleType.createTuple(null, "(null)", null);
        System.out.println("t1 = " + t1);
        System.out.println("t2 = " + t2);
        System.out.println("t3 = " + t3);
        System.out.println("tnull = " + tnull);

        final TupleType emptyTupleType =
            TupleType.DefaultFactory.create();

        final Tuple tempty = emptyTupleType.createTuple();
        System.out.println("\ntempty = " + tempty);

        // Should cause an error
        System.out.println("\nCreating tuple with wrong types: ");
        try {
            final Tuple terror = tripletTupleType.createTuple(1, 2, 3);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nCreating tuple with wrong # of arguments: ");
        try {
            final Tuple terror = emptyTupleType.createTuple(1);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nGetting value as wrong type: ");
        try {
            final Tuple t9 = tripletTupleType.createTuple(9, "nine", 'i');
            final String verror = t9.getNthValue(0);
            System.out.println("Getting this value should have failed: "+verror);
        } catch (ClassCastException ex) {
            ex.printStackTrace(System.out);
        }

    }

}

===
Sample Run
===
t1 = [1, one, a]
t2 = [2, two, b]
t3 = [3.0, three, c]
tnull = [null, (null), null]

tempty = []

Creating tuple with wrong types: 
java.lang.IllegalArgumentException: Expected value #1 ('2') of new Tuple to be class java.lang.String, not class java.lang.Integer
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:32)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:37)

Creating tuple with wrong # of arguments: 
java.lang.IllegalArgumentException: Expected 0 values, not 1 values
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:22)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:46)

Getting value as wrong type: 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:58)

Kudos on learning by doing. Here are suggestions of "opportunities" for improvement:

  1. Only one kind of Tuple can ever exist (once Typelock is set). This hurts reusability and scalability in programs wanting to use multiple types of Tuples unless you resort to cut-n-paste reuse (BirthdayTuple, DimensionsTuple, StreetAddressTuple, ...). Consider a TupleFactory class that accepts the target types and creates a tuple builder object to generate tuples.

  2. The validity of "null" as a value in a Tuple isn't documented. I think before Typelock is set, null is allowed; but after Typelock is set, code will generate a NullPointerException - this is inconsistent. If they are not allowed, the constructor should catch it and disallow it (regardless of Typelock). If they are allowed, then the code overall (constructor, equals, hashcode, etc) needs modification to allow for it.

  3. Decide whether Tuples are intended to be immutable value objects. Based on its lack of setter methods, I'd guess so. If so, then be careful of "adopting" the incoming array - lastTuple=this.arr. Even though its a var arg constructor, the constructor could be called with an array directly. The class adopts the array (keeps a reference to it) and the values in the array could be altered outside the class afterward. I'd do a shallow copy of the array, but also document the potential issue with Tuples with non-immutable values (that could be changed outside the Tuple).

  4. Your equals method lacks the null check (if (obj == null) return false) and the class check (either obj instanceof Tuple or this.getClass().equals(object.getClass())). The equals idiom is well documented.

  5. There's no way to view the values of a Tuple except through toString. This protects the values and the overall immutability of , but I think it limits the usefulness of the class.

  6. While I realize its just an example, I wouldn't expect to use this class for something like birthdays/dates. In solution domains with fixed object types, real classes (like Date) are so much better. I would imagine this class to be useful in specific domains where tuples are first class objects.

Edit
Been thinking about this. Here's my take on some code (on github + tests):

===
Tuple.java
===
package com.stackoverflow.tuple;

/**
 * Tuple are immutable objects.  Tuples should contain only immutable objects or
 * objects that won't be modified while part of a tuple.
 */
public interface Tuple {

    public TupleType getType();
    public int size();
    public <T> T getNthValue(int i);

}


===
TupleType.java
===
package com.stackoverflow.tuple;

/**
 * Represents a type of tuple.  Used to define a type of tuple and then
 * create tuples of that type.
 */
public interface TupleType {

    public int size();

    public Class<?> getNthType(int i);

    /**
     * Tuple are immutable objects.  Tuples should contain only immutable objects or
     * objects that won't be modified while part of a tuple.
     *
     * @param values
     * @return Tuple with the given values
     * @throws IllegalArgumentException if the wrong # of arguments or incompatible tuple values are provided
     */
    public Tuple createTuple(Object... values);

    public class DefaultFactory {
        public static TupleType create(final Class<?>... types) {
            return new TupleTypeImpl(types);
        }
    }

}


===
TupleImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

import java.util.Arrays;

class TupleImpl implements Tuple {

    private final TupleType type;
    private final Object[] values;

    TupleImpl(TupleType type, Object[] values) {
        this.type = type;
        if (values == null || values.length == 0) {
            this.values = new Object[0];
        } else {
            this.values = new Object[values.length];
            System.arraycopy(values, 0, this.values, 0, values.length);
        }
    }

    @Override
    public TupleType getType() {
        return type;
    }

    @Override
    public int size() {
        return values.length;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getNthValue(int i) {
        return (T) values[i];
    }

    @Override
    public boolean equals(Object object) {
        if (object == null)   return false;
        if (this == object)   return true;

        if (! (object instanceof Tuple))   return false;

        final Tuple other = (Tuple) object;
        if (other.size() != size())   return false;

        final int size = size();
        for (int i = 0; i < size; i++) {
            final Object thisNthValue = getNthValue(i);
            final Object otherNthValue = other.getNthValue(i);
            if ((thisNthValue == null && otherNthValue != null) ||
                    (thisNthValue != null && ! thisNthValue.equals(otherNthValue))) {
                return false;
            }
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 17;
        for (Object value : values) {
            if (value != null) {
                hash = hash * 37 + value.hashCode();
            }
        }
        return hash;
    }

    @Override
    public String toString() {
        return Arrays.toString(values);
    }
}


===
TupleTypeImpl.java (not visible outside package)
===
package com.stackoverflow.tuple;

class TupleTypeImpl implements TupleType {

    final Class<?>[] types;

    TupleTypeImpl(Class<?>[] types) {
        this.types = (types != null ? types : new Class<?>[0]);
    }

    public int size() {
        return types.length;
    }

    //WRONG
    //public <T> Class<T> getNthType(int i)

    //RIGHT - thanks Emil
    public Class<?> getNthType(int i) {
        return types[i];
    }

    public Tuple createTuple(Object... values) {
        if ((values == null && types.length == 0) ||
                (values != null && values.length != types.length)) {
            throw new IllegalArgumentException(
                    "Expected "+types.length+" values, not "+
                    (values == null ? "(null)" : values.length) + " values");
        }

        if (values != null) {
            for (int i = 0; i < types.length; i++) {
                final Class<?> nthType = types[i];
                final Object nthValue = values[i];
                if (nthValue != null && ! nthType.isAssignableFrom(nthValue.getClass())) {
                    throw new IllegalArgumentException(
                            "Expected value #"+i+" ('"+
                            nthValue+"') of new Tuple to be "+
                            nthType+", not " +
                            (nthValue != null ? nthValue.getClass() : "(null type)"));
                }
            }
        }

        return new TupleImpl(this, values);
    }
}


===
TupleExample.java
===
package com.stackoverflow.tupleexample;

import com.stackoverflow.tuple.Tuple;
import com.stackoverflow.tuple.TupleType;

public class TupleExample {

    public static void main(String[] args) {

        // This code probably should be part of a suite of unit tests
        // instead of part of this a sample program

        final TupleType tripletTupleType =
            TupleType.DefaultFactory.create(
                    Number.class,
                    String.class,
                    Character.class);

        final Tuple t1 = tripletTupleType.createTuple(1, "one", 'a');
        final Tuple t2 = tripletTupleType.createTuple(2l, "two", 'b');
        final Tuple t3 = tripletTupleType.createTuple(3f, "three", 'c');
        final Tuple tnull = tripletTupleType.createTuple(null, "(null)", null);
        System.out.println("t1 = " + t1);
        System.out.println("t2 = " + t2);
        System.out.println("t3 = " + t3);
        System.out.println("tnull = " + tnull);

        final TupleType emptyTupleType =
            TupleType.DefaultFactory.create();

        final Tuple tempty = emptyTupleType.createTuple();
        System.out.println("\ntempty = " + tempty);

        // Should cause an error
        System.out.println("\nCreating tuple with wrong types: ");
        try {
            final Tuple terror = tripletTupleType.createTuple(1, 2, 3);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nCreating tuple with wrong # of arguments: ");
        try {
            final Tuple terror = emptyTupleType.createTuple(1);
            System.out.println("Creating this tuple should have failed: "+terror);
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace(System.out);
        }

        // Should cause an error
        System.out.println("\nGetting value as wrong type: ");
        try {
            final Tuple t9 = tripletTupleType.createTuple(9, "nine", 'i');
            final String verror = t9.getNthValue(0);
            System.out.println("Getting this value should have failed: "+verror);
        } catch (ClassCastException ex) {
            ex.printStackTrace(System.out);
        }

    }

}

===
Sample Run
===
t1 = [1, one, a]
t2 = [2, two, b]
t3 = [3.0, three, c]
tnull = [null, (null), null]

tempty = []

Creating tuple with wrong types: 
java.lang.IllegalArgumentException: Expected value #1 ('2') of new Tuple to be class java.lang.String, not class java.lang.Integer
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:32)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:37)

Creating tuple with wrong # of arguments: 
java.lang.IllegalArgumentException: Expected 0 values, not 1 values
    at com.stackoverflow.tuple.TupleTypeImpl.createTuple(TupleTypeImpl.java:22)
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:46)

Getting value as wrong type: 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at com.stackoverflow.tupleexample.TupleExample.main(TupleExample.java:58)
梦里梦着梦中梦 2024-09-24 16:39:48

这种类型如何安全?您将引发运行时异常,而不是在编译时报告类型错误。

您正在尝试对数量进行抽象,这在静态类型语言中(到目前为止)是不可能的,而不失去类型安全性。

附录:

元组可以由异构元素(即具有不同类型的元素)组成。因此,对于这个 Tuple 类,提供“rutime 类型安全”是不可能的。班级的客户负责进行适当的演员阵容。

这是您在 Java 中可以做的最好的事情:编辑:请参阅Brent 的帖子,以更好地实现 Tuple。(它不需要在客户端进行类型转换。))

final class Tuple {
  private final List<Object> elements;

  public Tuple(final Object ... elements) {
    this.elements = Arrays.asList(elements);
  }

  @Override
  public String toString() {
    return elements.toString();
  }

  //
  // Override 'equals' and 'hashcode' here
  //

  public Object at(final int index) {
    return elements.get(index);
  }
}

How is this typesafe? You are throwing runtime exceptions instead of reporting type errors at compile time.

You are trying to abstract over arity which is (as of yet) not possible in statically typed languages, without losing typesafety.

Addendum:

Tuples can consist of heterogeneous elements (i.e. elements with different types). Therefore providing even "rutime typesafety" is not possible, for this Tuple class. Clients of the class are responsible for making the appropriate casts.

This is the best you can do in Java : (Edit: See Brent's post for a better implementation of Tuple. (It doesn't require typecasts on the client side.))

final class Tuple {
  private final List<Object> elements;

  public Tuple(final Object ... elements) {
    this.elements = Arrays.asList(elements);
  }

  @Override
  public String toString() {
    return elements.toString();
  }

  //
  // Override 'equals' and 'hashcode' here
  //

  public Object at(final int index) {
    return elements.get(index);
  }
}
拔了角的鹿 2024-09-24 16:39:48

这是最简单的解决方案,也是最好的解决方案。它类似于 .NET 中元组的表示方式。它小心翼翼地避开了java擦除。它是强类型的。它不会抛出异常。它非常容易使用。

public interface Tuple
{
    int size();
}

public class Tuple2<T1,T2> implements Tuple
{
    public final T1 item1;
    public final T2 item2;

    public Tuple2(
        final T1 item_1,
        final T2 item_2)
    {
        item1 = item_1;
        item2 = item_2;
    }

    @Override
    public int size()
    {
        return 2;
    }
}

public class Tuple3<T1,T2,T3> implements Tuple
{
    public final T1 item1;
    public final T2 item2;
    public final T3 item3;

    public Tuple3(
        final T1 item_1,
        final T2 item_2,
        final T3 item_3)
    {
        item1 = item_1;
        item2 = item_2;
        item3 = item_3;
    }

    @Override
    public int size()
    {
        return 3;
    }
}

This is the simplest solution and it's also the best. It's similar to how Tuples are represented in .NET. It carefully sidesteps java erasure. It is strongly typed. It does not throw exceptions. It is very easy to use.

public interface Tuple
{
    int size();
}

public class Tuple2<T1,T2> implements Tuple
{
    public final T1 item1;
    public final T2 item2;

    public Tuple2(
        final T1 item_1,
        final T2 item_2)
    {
        item1 = item_1;
        item2 = item_2;
    }

    @Override
    public int size()
    {
        return 2;
    }
}

public class Tuple3<T1,T2,T3> implements Tuple
{
    public final T1 item1;
    public final T2 item2;
    public final T3 item3;

    public Tuple3(
        final T1 item_1,
        final T2 item_2,
        final T3 item_3)
    {
        item1 = item_1;
        item2 = item_2;
        item3 = item_3;
    }

    @Override
    public int size()
    {
        return 3;
    }
}
撩发小公举 2024-09-24 16:39:48

您应该查看.NET 的 Tuple 实现。它们是编译时类型安全的。

You should look at .NET's Tuple's implementation. They are compile time type-safe.

把梦留给海 2024-09-24 16:39:48

typeLock 的用途是什么?允许某人阻止建造更多这些物体?这部分没有多大意义。

为什么你想让别人阻止你的对象的进一步实例化?如果由于某种原因这是您所需要的,而不是“锁定”类并引发异常,只需确保代码路径...不会创建更多该类型的对象。

将静态 lastTuple 设置为最后实例化 Tuple 的引用的目的是什么?像这样混合静态引用是一种糟糕的做法。

坦率地说,代码相当混乱,尽管对这个类的需求很混乱。如果不知何故这是我在工作环境中审查的代码,我不会允许它。

What is the purpose of typeLock? To allow someone to prevent constructing any more of these objects? This part doesn't make much sense.

Why would you ever want to let someone prevent further instantiation of your objects? If for some reason this is something you ever need, instead of "locking" a class and throwing exceptions, just make sure the code path ... doesn't create more objects of the type.

What's the purpose of the static lastTuple which is set to a reference of the last instantiated Tuple? It's a poor practice to mix static references like this.

Frankly the code is quite confusing, even though the need for this class is confusing. If somehow this was code I was reviewing in a work environment, I would not allow it.

泛泛之交 2024-09-24 16:39:48

为了编译时类型安全,最好使用泛型。您可以为每个数量定义一个接口。然后,您可以定义单独的 Callable 接口来访问元组的值。

interface Tuple1 <T0> { <R> R accept ( Callable1<R,T0> callable ) ; }

interface Tuple2 <T0,T1> { <R> R accept ( Callable2<R,T0,T1> callable ) ; }

...

interface Tuplek <T0,T1,T2,...,Tk> { <R> R accept ( Callablek<R,T0,T1,T2,...,Tk> callable ) ; }

interface Callable1<R,T0> { R call ( T0 t0 ) ; }

interface Callable2<R,T0> { R call ( T0 t0 , T1 t1 ) ; }

....

interface Callablek<R,T0,T1,T2,...,Tk> { R call ( T0 t0 , T1 t1 , T2 t2 , ... , Tk tk ) ; }

It would be better to use generics for compile time type safety. You can define one interface per arity. Then you can define separate Callable interfaces to access the values of the tuple.

interface Tuple1 <T0> { <R> R accept ( Callable1<R,T0> callable ) ; }

interface Tuple2 <T0,T1> { <R> R accept ( Callable2<R,T0,T1> callable ) ; }

...

interface Tuplek <T0,T1,T2,...,Tk> { <R> R accept ( Callablek<R,T0,T1,T2,...,Tk> callable ) ; }

interface Callable1<R,T0> { R call ( T0 t0 ) ; }

interface Callable2<R,T0> { R call ( T0 t0 , T1 t1 ) ; }

....

interface Callablek<R,T0,T1,T2,...,Tk> { R call ( T0 t0 , T1 t1 , T2 t2 , ... , Tk tk ) ; }
枫林﹌晚霞¤ 2024-09-24 16:39:48

在wave项目中看到这段代码

public class Tuple<A> {

  private final A[] elements;

  public static <A> Tuple<A> of(A ... elements) {
    return new Tuple<A>(elements);
  }

  public Tuple(A ... elements) {
    this.elements = elements;
  }

  public A get(int index) {
    return elements[index];
  }

  public int size() {
    return elements.length;
  }

  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }

    if (o == null || o.getClass() != this.getClass()) {
      return false;
    }

    Tuple<A> o2 = (Tuple<A>) o;
    return Arrays.equals(elements, o2.elements);
  }

  @Override
  public int hashCode() {
    return Arrays.hashCode(elements);
  }

  @Override
  public String toString() {
    return Arrays.toString(elements);
  }
}

saw this code in wave project

public class Tuple<A> {

  private final A[] elements;

  public static <A> Tuple<A> of(A ... elements) {
    return new Tuple<A>(elements);
  }

  public Tuple(A ... elements) {
    this.elements = elements;
  }

  public A get(int index) {
    return elements[index];
  }

  public int size() {
    return elements.length;
  }

  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }

    if (o == null || o.getClass() != this.getClass()) {
      return false;
    }

    Tuple<A> o2 = (Tuple<A>) o;
    return Arrays.equals(elements, o2.elements);
  }

  @Override
  public int hashCode() {
    return Arrays.hashCode(elements);
  }

  @Override
  public String toString() {
    return Arrays.toString(elements);
  }
}
埋葬我深情 2024-09-24 16:39:48

这是一个非常糟糕的 n 元组实现,它使用泛型来提供编译时类型检查。主要方法(出于演示目的而提供)展示了使用它是多么可怕:

interface ITuple { }

/**
 * Typed immutable arbitrary-length tuples implemented as a linked list.
 *
 * @param <A> Type of the first element of the tuple
 * @param <D> Type of the rest of the tuple
 */
public class Tuple<A, D extends ITuple> implements ITuple {

    /** Final element of a tuple, or the single no-element tuple. */
    public static final TupleVoid END = new TupleVoid();

    /** First element of tuple. */
    public final A car;
    /** Remainder of tuple. */
    public final D cdr;

    public Tuple(A car, D cdr) {
        this.car = car;
        this.cdr = cdr;
    }

    private static class TupleVoid implements ITuple { private TupleVoid() {} }

    // Demo time!
    public static void main(String[] args) {
        Tuple<String, Tuple<Integer, Tuple<String, TupleVoid>>> triple =
                new Tuple<String, Tuple<Integer, Tuple<String, TupleVoid>>>("one",
                        new Tuple<Integer, Tuple<String, TupleVoid>>(2,
                                new Tuple<String, TupleVoid>("three",
                                        END)));
        System.out.println(triple.car + "/" + triple.cdr.car + "/" + triple.cdr.cdr.car);
        //: one/2/three
    }
}

Here's a truly awful n-tuple implementation that uses generics to provide compile-time type checks. The main method (provided for demo purposes) shows just how horrendous this would be to use:

interface ITuple { }

/**
 * Typed immutable arbitrary-length tuples implemented as a linked list.
 *
 * @param <A> Type of the first element of the tuple
 * @param <D> Type of the rest of the tuple
 */
public class Tuple<A, D extends ITuple> implements ITuple {

    /** Final element of a tuple, or the single no-element tuple. */
    public static final TupleVoid END = new TupleVoid();

    /** First element of tuple. */
    public final A car;
    /** Remainder of tuple. */
    public final D cdr;

    public Tuple(A car, D cdr) {
        this.car = car;
        this.cdr = cdr;
    }

    private static class TupleVoid implements ITuple { private TupleVoid() {} }

    // Demo time!
    public static void main(String[] args) {
        Tuple<String, Tuple<Integer, Tuple<String, TupleVoid>>> triple =
                new Tuple<String, Tuple<Integer, Tuple<String, TupleVoid>>>("one",
                        new Tuple<Integer, Tuple<String, TupleVoid>>(2,
                                new Tuple<String, TupleVoid>("three",
                                        END)));
        System.out.println(triple.car + "/" + triple.cdr.car + "/" + triple.cdr.cdr.car);
        //: one/2/three
    }
}
通知家属抬走 2024-09-24 16:39:48

如果您真的对编写类型安全容器感兴趣,请研究泛型:

public class Tuple<T> {
  private final T[] arr;
  public Tuple (T... contents) {
    arr = contents;  //not sure if this compiles??
  }

  // etc

  public static final void main(String[] args) {
    Tuple<String> stringTuple = new Tuple<String>("Hello", "World!");
    Tuple<Integer> intTuple = new Tuple<Integer>(2010,9,4);
  }
}

If you're really interested in writing type-safe containers, look into generics:

public class Tuple<T> {
  private final T[] arr;
  public Tuple (T... contents) {
    arr = contents;  //not sure if this compiles??
  }

  // etc

  public static final void main(String[] args) {
    Tuple<String> stringTuple = new Tuple<String>("Hello", "World!");
    Tuple<Integer> intTuple = new Tuple<Integer>(2010,9,4);
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文