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

发布于 2024-10-21 23:53:48 字数 645 浏览 8 评论 0原文

我希望了解为什么Java 设计者选择以这种方式实现函数声明。我经常听说 Java 的设计者希望避免其他语言(例如 C++)中做出的糟糕设计选择——通过类的多重继承运算符重载我想到的是——为了保持面向对象模型尽可能简单并鼓励良好的编程实践。在本案中是这样吗?此功能是否太昂贵而无法实现其提供的(无可否认的边际)收益?

问题是,我看不到(而且我仍在学习,所以这可能意味着蹲下!:D)允许在函数声明中省略形式参数名称的重大实现开销。我至少可以想到一个例子,这个特性不会造成伤害:定义抽象函数。

不管怎样,很高兴听到人们对 SO 的一些想法。顺便说一句,相关部分 (8.4.1) Java 语言规范的 解释了是什么,但没有谈论为什么

编辑:添加代码片段:

abstract void someFunc(int, int, int);

(我正在使用抽象函数,因为这是一个简单的情况,我可以想到此功能在哪里会很方便)。

I'm looking to understand why Java designers chose to implement function declarations this way. I've often heard it said that the designers of Java wanted to avoid poor design choices made in other languages (e.g., C++) -- multiple inheritance via classes and operator overloading come to mind -- in order to keep the object-oriented model as simple as possible and to encourage good programming practices. Is that true in this case? Is this feature too expensive to implement vis-a-vis the (admittedly marginal) gains it provides?

The thing is, I can't see (and I'm still learning, so that probably means squat! :D) a significant implementation overhead in allowing the omission of formal parameter names in function declarations. And I can think of at least one example where this feature couldn't hurt: defining abstract functions.

Anyway, glad to hear some thoughts from people on SO. BTW, the relevant section (8.4.1) of the Java Language Specification explains what but doesn't talk about why.

EDIT: Adding a code snippet:

abstract void someFunc(int, int, int);

(I'm using an abstract function as this is one simple case I can think of where this feature would be handy).

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

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

发布评论

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

评论(6

昨迟人 2024-10-28 23:53:48

为什么应该允许这样做?

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

在 C 中,情况略有不同:声明和实现彼此独立(至少如果你做得“正确”的话)。在这里,将信息保留在一处可以避免重复。

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

Why should it allow this?

If a method definition had no names for its parameters, how would you actually use the parameters in your code?

In C the situation is slightly different: you have the declaration and the implementation independently of each other (at least if you do it "right"). Here, leaving the information out in one place avoids duplication.

But in Java there is no separate declaration (unless you're defining a method in an interface, in which case there's no implementation, which means no duplication again). There's only the implementation.

夜无邪 2024-10-28 23:53:48

您可以通过使用重载来删除正式参数,例如

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 设计倾向于等待一个令人信服的理由去做某事(然后再考虑几年;)一个为什么不的论点不足以包含某件事。通常还有其他方法可以做同样的事情(如果不是那么优雅),例如使用重载,这使得情况不那么引人注目

You can drop formal arguments by using overloading e.g.

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) { }
}

EDIT: From my comment.

The Java design tends to wait for a compelling reason to do something (and then think about it for a few more years ;) A why not argument is not enough to include something. There are generally other ways of doing the same thing (if not as elegent) such as using overloading instead, which makes the case less than compelling

童话 2024-10-28 23:53:48

不同的答案表明您并不清楚您要问什么 - 在问题中举个例子会有所帮助。

我假设您希望能够编写

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

而不是

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

在方法中的任何地方不使用 bc 时(或者该方法是抽象的,或类似的)。

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

  • 这会使语法复杂化(虽然不会太复杂),
  • 通常您会想要记录参数,为此您需要它们的名称。 (这也适用于接口和抽象/本机方法。)
  • 当不使用参数时,为什么要使用它们呢?
  • 从理论角度来看:形式参数声明是一种变量声明,并且不能有没有名称的变量(数组元素除外)。
  • 它可能会让代码的读者感到困惑。

当我有未使用的参数时,我有时会给它们命名,例如 ignoreddummy

The different answers show it is not really clear what you are asking about - putting an example in the question would have helped.

I assume you would want to be able to write

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

instead of

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

whenever b and c are not used anywhere in the method (or the method is abstract, or similar).

So, why not allow omitting them:

  • It would complicate the grammar (not much, though)
  • Often you would want to document the arguments, and for this you would need names for them. (This applies to interfaces and abstract/native methods, too.)
  • When arguments are not used, why have them at all?
  • From a theoretical viewpoint: Formal parameter declarations are a kind of variable declaration, and you can't have a variable without a name (apart from array elements).
  • It could confuse readers of the code.

When I have arguments which are not used, I sometimes give them names like ignored or dummy.

悲念泪 2024-10-28 23:53:48

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

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

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”成为三个或四个数字,则应该单独创建这些方法。

也许这是一个糟糕的人为示例,但我的部分观点是同意这种语言功能并不总是有意义。

I think it's just part of the same philosophy that makes things strongly typed, for instance. You are expected to know what a method is and how you're using it at compile-time.

It's about having an interface that always takes the parameters you expect and returns the results you expect and throws the exceptions you expect. If we have

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;}
}

Then the designers of Java are thinking: if you want to "Adder.add" two specific numbers, there's a method for that. You would never call this method with three or four parameters, because that just makes no sense for what that method is designed to do. If you want to make "Adder.add"s three or four numbers, you should make those methods separately.

Now perhaps this is a terrible contrived example, but part of my point was to agree that this language feature doesn't always make sense.

暮凉 2024-10-28 23:53:48

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

当然,如果您只命名参数 ab,您的代码也可以正常工作,但您没有这样做。您称它们为国家出生地。你用它来传达意义。

Java 的目的始终是迫使程序员尽可能做正确的事情,并且避免搬起石头砸自己的脚。这就是为什么它是这样设计的。

If you're talking about the names, not the arguments themselves, the reason is simple. When defining abstract methods you are defining an interface. For an interface to be usable, the person addressing it has to know the meaning of the arguments. That's what the names are for.

Sure, your code could work just as well if you would just name your arguments a and b, but you don't. You call them country or birthplace. You use it to convey meaning.

Java was always meant to force programmers to do the right thing as much as possible, and to make it hard to shoot yourself in the foot. That's why it was designed like this.

别忘他 2024-10-28 23:53:48

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

假设我有这个:

@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 );

当然,如果能够省略未使用的参数的名称,那就太好了。在这种情况下,不必重载或使用注释来忽略警告或其他内容。

It would be a great feature, because you could get rid of that stupid annotation to ignore unused.

Let's say I had this:

@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() );
    ...

So, the simple case:

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

But what about unit tests?

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 );

Sure would be nice to be able to omit the name for the unused parameter. Instead of having to overload, or use annotations to ignore the warning in this case, or other stuff.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文