我希望了解 为什么 Java设计人员选择以这种方式实现函数声明。我经常听到它说Java的设计者想避免在其他语言中做出糟糕的设计选择(例如,C ++) - 通过类和运算符重载的多重继承浮现在脑海中 - 为了使面向对象的模型尽可能简单并鼓励良好的编程实践。在这种情况下是真的吗?这个功能是否过于昂贵,无法实现相对于它所提供的(无可否认的边际)收益?
问题是,我看不到(我还在学习,所以这可能意味着蹲下!:D)一个重要的实现开销,允许在函数声明中省略形式参数名称。我至少可以想到这个功能不会受到影响的一个例子:定义抽象函数。
无论如何,很高兴听到人们对SO的一些想法。 BTW,the relevant section (8.4.1) Java语言规范解释了什么但没有谈论为什么。
编辑:添加代码段
abstract void someFunc(int, int, int);
(我正在使用一个抽象函数,因为这是一个简单的例子,我可以想到这个特性在哪里很方便)。
答案 0 :(得分:3)
为什么 它允许这个?
如果方法定义没有其参数的名称,您将如何在代码中实际使用这些参数?
在C中,情况略有不同:你有相互独立的声明和实现(至少如果你这样做“正确”)。在这里,将信息留在一个地方可以避免重复。
但是在Java中没有单独的声明(除非你在接口中定义一个方法,在这种情况下没有实现,这意味着没有重复)。只有 的实现。
答案 1 :(得分: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设计倾向于等待令人信服的理由去做一些事情(然后再考虑几年;)为什么不参数不足以包含某些东西。通常还有其他方法可以做同样的事情(如果不是那样),比如使用重载,这会使案例不那么引人注目
答案 2 :(得分:0)
不同的答案表明你所询问的内容并不十分清楚 - 在问题中加上一个例子会有所帮助。
我假设您希望能够写
public void method(int a, int, int) {
}
而不是
public void method(int a, int b, int c) {
}
每当b
和c
未在方法中的任何位置使用时(或方法是抽象的或类似的)。
那么,为什么不允许省略它们:
如果我有不使用的参数,我有时会给它们命名为ignored
或dummy
。
答案 3 :(得分: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”的三个或四个数字,你应该单独制作这些方法。
现在也许这是一个可怕的人为例子,但我的一部分意见是同意这种语言特征并不总是有意义的。
答案 4 :(得分:0)
如果你在谈论名称,而不是论据本身,原因很简单。定义抽象方法时,您正在定义一个接口。要使接口可用,寻址它的人必须知道参数的含义。这就是名字的用途。
当然,如果您只是将参数命名为 a 和 b ,那么您的代码也可以正常工作,但事实并非如此。您将其称为 country 或 birthplace 。你用它来传达意义。
Java总是意味着迫使程序员尽可能地做正确的事情,并且难以让自己陷入困境。这就是为什么它是这样设计的。
答案 5 :(得分: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 );
当然可以省略未使用参数的名称。
,而不是必须重载,或使用注释忽略此情况下的警告。