Seltsamer Array-Rückgabetyp

72

Hat jemand das Array so gesehen, das []nach der Methodensignatur platziert wurde?

public static String mySplit(String s)[] {
    return s.split(",");
}

public static void main(String... args) {
    String[] words = mySplit("a,b,c,d,e");
    System.out.println(Arrays.toString(words));
}

druckt

[a, b, c, d, e]

In der Vergangenheit gab es ungerade Notationen für die "C" -Kompatibilität, aber ich würde mir nicht vorstellen, dass jemand dies in C schreibt.

Weiß jemand warum das überhaupt erlaubt ist?

Ich verwende Java 7 Update 10, falls es darauf ankommt.

Dies funktioniert auch in Java 6. http://ideone.com/91rZV1


Übrigens wird dies nicht kompiliert, und ich würde es auch nicht erwarten

public static <T> List mySplit(String s)<T> {
    return Collections.emptyList();
}
Peter Lawrey
quelle
3
Ich könnte mir vorstellen, dass ein C-Programmierer diese Schrecklichkeit schreibt. C ++ ist bekannt für seine seltsame Syntax, wenn es um Typen geht, insbesondere um Array-Typen, insbesondere in Kombination mit Funktionszeigertypen.
John Dvorak
1
Beachten Sie, dass dies inx x[10]genau das gleiche Problem ist, außer dass es weniger übertrieben ist
John Dvorak
Der Code wird nicht einmal kompiliert.
Roman C
1
@ RomanC Ich sehe kein Problem mit einer Klasse, die beide toStringund hat static toString(String). Sie haben jedoch Recht - haben diesen Aufruf nicht bemerkt oder den Methodennamen als verdächtig empfunden.
John Dvorak
1
Als ich Java lernte, tat 'javap' dies standardmäßig. Es hat mich immer verwirrt, warum (und das Lesen der Ausgabe viel schwieriger gemacht).
Owen

Antworten:

90

Weiß jemand warum das überhaupt erlaubt ist?

In diesem Fall dient dies der Abwärtskompatibilität mit Java. Aus dem JLS-Abschnitt 8.4 :

Aus Gründen der Kompatibilität mit älteren Versionen der Java SE-Plattform darf die Deklaration einer Methode, die ein Array zurückgibt, (einige oder alle) leere Klammerpaare, die die Deklaration des Array-Typs bilden, nach der formalen Parameterliste platzieren. Dies wird durch die folgende veraltete Produktion unterstützt, sollte jedoch nicht in neuem Code verwendet werden.

Und ja, Sie sollten es in der Tat als einen Gräuel betrachten, der keinen anderen Zweck hat, als andere Entwickler zu schockieren. Vielleicht können Sie damit Geld auf Partys gewinnen, indem Sie darauf wetten, dass es gegen Leute kompiliert wird, die es noch nie gesehen haben ...

Hier ist die Art von Methode, die von vernünftigen Codierern als ungültig erwartet wird:

public String[] mwahahaha(String[] evil[])[] {
    return evil;
}
Jon Skeet
quelle
@ nicholas.hauschild Ich esse am Donnerstag mit einer Menge Java-Entwickler zu Abend. Das muss fast zählen. ;)
Peter Lawrey
1
@ PeterLawrey warum nicht (String[]... evil[])?
John Dvorak
3
@ PeterLawrey: Ich habe versucht, beide zu mischen, bekam aber: "Legacy-Array-Notation für Parameter mit variabler Arität nicht zulässig"
Jon Skeet
4
@ JanDvorak Die meisten Entwickler sind ziemlich gut darin, statische Analysen und Compiler-Warnungen zu ignorieren, die ich finde.
Peter Lawrey
1
@PeterLawrey Es gibt einen Unterschied zwischen einem "bloßen" gelben Dreieck in der linken Rinne und einer durchgezogenen schwarzen Linie über den gesamten Methodennamen. Letzteres kann man nicht so leicht übersehen.
John Dvorak
19

Es ist wie

  String[] a; 

ist das gleiche wie

  String a[];

Gleiches gilt für die Syntax von Methodenrückgabetypen

  public static String mySplit(String s)[] {

ist das gleiche wie

  public static String[] mySplit(String s) {

Aber ich glaube, ich habe die Version, die Sie im Produktivcode erwähnt haben, noch nie gesehen.

MrSmith42
quelle
2
Ich glaube auch nicht, dass ich es jemals gesehen habe. sollte ich, ich poste zu TDWTF
John Dvorak
6

Ich denke, es ist der gleiche Grund, warum die folgenden Variablendeklarationen beide gleichwertig sind

String[] array
String array[]

Dies ist eine Sache, die C-Entwickler tun, daher wurde sie aufgenommen, um ihnen zu helfen.

Peter Elliott
quelle
2
"Dies ist eine Sache, die C-Entwickler tun, daher wurde sie aufgenommen, um ihnen zu helfen." <- Wenn Sie Literatur zu diesem bestimmten Punkt hätten, hätte ich gerne Hinweise, es könnte eine lustige Lektüre sein! (
Zumal
4

Ich glaube, es sagt Java nur, dass der Rückgabetyp ein Array von ist Strings, genau wie das Deklarieren

static String[] mySplit(String s) {...

Ähnlich wie beim Deklarieren von Variablen:

String myStringArray[];

ist äquivalent zu

String[] myStringArray;
Setzen Sie Monica wieder ein - notmaynard
quelle
4

Gute Frage; Als ich einen Java-Parser implementiert habe, erinnere ich mich, dass mich die JLS-Grammatik an dieser Stelle wirklich verwirrt hat.

Um Johns Antwort zu erweitern, gehen Sie wie folgt vor:

Es gibt (mindestens) 5 Stellen, an denen dies wichtig ist:

  • Methodensignaturen
  • lokale Variablendeklarationen
  • Felddeklarationen
  • formale Parameter
  • for-schleifen

Hier ist ein Auszug aus der Grammatik, der sich auf Methodendeklarationen konzentriert:

MethodOrFieldDecl:
    Type Identifier MethodOrFieldRest

MethodOrFieldRest:  
    FieldDeclaratorsRest ;
    MethodDeclaratorRest

MethodDeclaratorRest:
    FormalParameters {[]} [throws QualifiedIdentifierList] (Block | ;)

Type:
    BasicType {[]}
    ReferenceType  {[]}

(Warnung: Es ist schwierig, die Grammatik zu lesen, da die eckigen und geschweiften Klammern manchmal Literale und manchmal Metazeichen sind.)

Dies zeigt, dass []dies sowohl unter der TypeRegel als auch als Teil der MethodDeclaratorRestRegel angezeigt werden kann. Es ist an beiden Stellen optional.

Matt Fenwick
quelle
1

Ja, das ist erlaubt,

der gleiche Grund, dass:

String[] myArray;

ist äquivalent zu

String myArray[];
Ahmed Kato
quelle