在Java中,如何根据方法的情况返回String或double?这是否可能?

3
例如,我有一个方法,它会查找由特定分隔符分隔的数据字符串,但有些项可能是名称,而其他项可能是数字。
如果用户调用我的方法来返回分隔列表中的第X项,如果项X是名称,我希望它返回一个字符串,如果项X是数字,则返回一个双精度浮点数。
例如,objectName.get(5);将获取分隔列表中的第5项。
我需要使用某种重载方式吗?
还是基于用户知道第5项是什么,我需要执行类似于objectName.getDouble(5);objectName.getString(5);这样的操作?
但是,如果用户不知道第5项是什么,他只需要根据实际情况获得字符串或双精度浮点数。
4个回答

7
这里有一种方法可以实现这个目标:
public Object get() {
    if (blueMoon) {
        return new Double(42.0);
    } else {
        return "fred";
    }
}

请注意,这将返回一个包装类Double而不是一个基本类型double
然而我认为这不是一个好主意,因为调用者现在必须测试返回值的类型并进行类型转换才能对其进行操作。
值得一提的是,在Java类型系统中,Stringdouble没有共同的超类型,因此Java不允许方法返回它们。

有趣!不过我不理解你的第二个陈述...我经常返回字符串和双精度浮点数。你是说如果返回类型是“Object”,就不能返回一个字符串或双精度浮点数吗? - trusktr
2
如果你的返回类型是Object,那么你可以从这个方法中返回任何继承自Object基类的东西。问题在于调用者不知道你返回的类型,所以调用者必须进行类型检查和转换才能从返回值中获得有用的信息。这并没有什么问题,但可能有更简洁的方法来解决它。 - Andy White
哎呀,我本来想将Double强制转换为double的。这是个笔误,呵呵。它会自动拆箱,对吧?所以double d = x.get() - trusktr
6
我也“怀念”PHP在复杂应用程序中的运行时惊喜 :) - cherouvim
1
@trusktr:不行 - 在这里,未经类型转换,无法使用unbox。所以 double d = (Double) x.get();。当然,类型转换可能会抛出未检查的异常。 - Stephen C
显示剩余4条评论

6

对于这种情况,我更喜欢使用类似于函数式编程阵营中的Maybe/Option模式。你最终会得到一个接口,如下:

public abstract class DoubleOrString 
{
    // Constraint isDouble() xor isString()
    public boolean isDouble();
    public boolean isString();

    //Must throw iff !isString()
    public String getString();

    //Must throw iff !ifDouble()
    public Double getDouble();

    public static DoubleOrString wrap(final double wrapMe)
    {
       return new DoubleOrString()
       {
             public boolean isDouble() {return true;}
             public boolean isString() {return false;}
             public Double getDouble() {return wrapMe;}
             public String getString() {throw new RuntimeException();}
       };
    }

    //same for wrap(String)
}

这对客户来说是一种强制性的要求,因为必须在适当的时间进行双倍或字符串的检查。在您的情况下,我会制作一个get()方法,这样当客户端(认为他们)知道类型时,调用就是

objectName.get(5).getString();

在你的get(int)方法中,不要返回字符串或双精度浮点数,而是使用以下返回语句。
DoubleOrString.wrap(theThingToReturn)

这需要一些额外的工作量,但它曾经多次为我带来了回报。

下面是如何使用它来构建一个(警告 - 它没有接近编译器)

public static DoubleOrString parseADoubleOrString(String input) {
    try {
        return DoubleOrString.wrap(Integer.parseInt(input))
    } catch (NumberFormatException nfe) {
        return DoubleOrString.wrap(input);
    }
}

以下是客户端的样子:

  String input = //get the input from the user somehow
  DoubleOrString parsed = parseADoubleOrString(input);
  if (parsed.isDouble())
      aFunctionThatTakesADouble(parsed.getDouble());
  else
      aFunctionThatTakesAString(parsed.getString());

哇,这看起来很有趣。我以前从未见过这样的结构。你能否编辑答案并解释一下它是如何工作的? - trusktr
1
如果您尝试编译并在调试器中使用它,那么您将会从中获得更多的收益。您想了解哪一部分的解释?由于您提供的问题没有太多上下文可供阐述。 - Burleigh Bear
我猜我还不了解足够的Java,甚至不知道该问什么呵呵。我只做了4周的JAVA。但我肯定会把这个记下来的。现在,我只输出字符串,让客户端自己转换成double。 - trusktr
Burleigh Bear,我从未有机会尝试过这个... 我肯定甚至知道如何使用这个类。你能发布一个用法示例吗? - trusktr

2
如果您需要这样做,那么您的设计存在问题。由于原始数据源是字符串,您必须接受所有返回值都将是字符串,并留给客户端检查结果是否可以转换为数字。
如果您想避免客户端进行检查,可以为其提供最小的API,可能如下所示:
public class ValueExtractor {

    public ValueExtractor(String delimitedText) {
        // ...
    }

    /**
     * Determines whether there is a next element
     * to be returned
     */
    public boolean next() {
        // ...
    }

    public String get() {
        // ...
    }

    /**
     * Returns the value as a Double if possible
     * null otherwise.
     */
    public Double getPossibleDouble() {
        // ...
    }
}

如果您需要这样做,那么可能存在设计问题。 - andersoj

0

Java语言不支持方法返回类型的重载。(正如Thilo所指出的,这是Java语言的限制,而不是JVM/字节码的限制。)

一般来说,这种类型的东西不太适合Java类型系统。人们可以想象返回一个Either<String,Double>类型(比Stephen C建议的Object类型更受限制,比B. Bear指出的DoubleOrString类型更通用),但在Java中使用这样的结构所需的一般性努力通常会导致只有多个方法,例如getString(...)getDouble(...)


确实如此。我只想能够在一开始不知道返回类型的情况下获取任何东西。 - trusktr
@trusktr - 这是假设性的 - Stephen C
3
Java语言不允许对方法的返回类型进行重载,但JVM支持此功能。 - Thilo
@Thilo 是这样吗?有没有办法利用它? - trusktr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接