为什么Java不允许在函数声明中省略形式参数名称?

问题描述 投票:1回答:6

我想了解为什么Java设计者选择以这种方式实现函数声明。我经常听到它说Java的设计者想避免在其他语言中做出糟糕的设计选择(例如,C ++) - 通过类和运算符重载进行多重继承 - 为了保持面向对象的模型尽可能简单并鼓励良好的编程实践。在这种情况下是真的吗?相对于它提供的(公认的边际)收益,这个功能是否过于昂贵?

问题是,我看不到(我还在学习,所以这可能意味着蹲下!:D)一个重要的实现开销,允许在函数声明中省略形式参数名称。我至少可以想到这个功能不会受到影响的一个例子:定义抽象函数。

无论如何,很高兴听到人们对SO的一些想法。顺便说一下,Java语言规范的the relevant section (8.4.1)解释了什么,但没有谈到原因。

编辑:添加代码段:

abstract void someFunc(int, int, int);

(我正在使用抽象函数,因为这是一个简单的例子,我可以想到这个特性会派上用场)。

java methods arguments declaration
6个回答
1
投票

您可以使用重载例如删除正式参数

class Three {
  public Three() {
    this(1);
  }

  public Three(int a) {
    this(a, 2);
  }

  public Three(int a, int b) {
    this(a, b, 3);
  }

  public Three(int a, int b, int c) {  }

  // can pass any number of `int` values.
  public void method1(int... varargs) {
  }

  public void method2(int a) {
     method2(a, 2);
  }

  public void method2(int a, int b) { }
}

编辑:从我的评论。

Java设计倾向于等待令人信服的理由去做一些事情(然后再思考几年;)为什么不参数不足以包含某些东西。通常还有其他方法可以做同样的事情(如果不是那样),例如使用重载,这使得案例不那么引人注目


3
投票

它为什么要允许这个?

如果方法定义没有其参数的名称,您将如何在代码中实际使用这些参数?

在C中,情况略有不同:您具有彼此独立的声明和实现(至少如果您“正确”执行)。在这里,将信息留在一个地方避免了重复。

但是在Java中没有单独的声明(除非你在接口中定义一个方法,在这种情况下没有实现,这意味着没有重复)。只有实施。


0
投票

不同的答案表明你所询问的内容并不是很清楚 - 在问题中加上一个例子会有所帮助。

我想你会希望能够写作

public void method(int a, int, int) {
}

代替

public void method(int a, int b, int c) {
}

每当bc在方法中的任何地方都没有使用(或者方法是抽象的或类似的)。

那么,为什么不允许省略它们:

  • 它会使语法复杂化(尽管不多)
  • 通常你会想要记录参数,为此你需要为它们命名。 (这也适用于接口和抽象/本机方法。)
  • 当不使用参数时,为什么要使用它们?
  • 从理论的角度来看:形式参数声明是一种变量声明,你不能有一个没有名字的变量(除了数组元素)。
  • 它可能会使读者感到困惑。

当我有没有使用的参数时,我有时给它们像ignoreddummy这样的名字。


0
投票

例如,我认为这只是使得强类型化的同一哲学的一部分。您需要知道方法是什么以及如何在编译时使用它。

它是关于拥有一个总是接受您期望的参数的接口并返回您期望的结果并抛出您期望的异常。如果我们有

class Adder {
    int add(int a, int b) {return a+b;}
    int add(int a, int b, int c) {return a+b+c;}
    int add(int a, int b, int c, int d) {return a+b+c+d;}
}

然后Java的设计者正在思考:如果你想要“Adder.add”两个特定的数字,那就有一种方法。您永远不会使用三个或四个参数调用此方法,因为这对于该方法的设计没有任何意义。如果你想制作“Adder.add”的三个或四个数字,你应该分别制作这些方法。

现在也许这是一个可怕的人为例子,但我的一部分意见是同意这种语言特征并不总是有意义的。


0
投票

如果你在谈论名称,而不是论证本身,原因很简单。定义抽象方法时,您正在定义一个接口。要使接口可用,寻址它的人必须知道参数的含义。这就是名字的用途。

当然,如果您只是将参数命名为a和b,那么您的代码也可以正常工作,但事实并非如此。你称他们为国家或出生地。你用它来传达意义。

Java总是意味着迫使程序员尽可能地做正确的事情,并且难以让自己陷入困境。这就是为什么它是这样设计的。


0
投票

这将是一个很棒的功能,因为你可以摆脱那个愚蠢的注释来忽略未使用的。

假设我有这个:

@FunctionalInterface
interface ListFunc {
    Stream<Path> apply( Path dir ) throws IOException;
}
void doStuff( Path dir, ListFunc listFunc ) {
    List<Path> filenames = listFunc.apply( dir ).collect( Collectors.toList() );
    ...

所以,简单的情况:

doStuff( Paths.get( System.getProperty( "user.home" ) ), Files::list );

但是单元测试怎么样?

static Stream<Path> fixedListFunc( Path /* unused */ dir ) {
    List<Path> fixed = Lists.newArrayList( Paths.get( "first" ),
            Paths.get( "second" ),
            Paths.get( "third" ) );
    return fixed.stream();
}

@Test
public void testDoStuff() {
    doStuff( null, fixedListFunc );

当然可以省略未使用参数的名称。而不是必须超载,或使用注释来忽略此情况下的警告或其他东西。

© www.soinside.com 2019 - 2024. All rights reserved.