Hi,
ich habe gerade ein bisschen mit der Pr-Release von Java8 gespielt und mich sehr gewundert: Mein Code funktionierte nicht mehr, da grundlegende Funktionen andere Resultate erbringen:
Wendet man die Funktion split("") auf einen String an, also z.B.:
String[] letters = text.split("");```
... so ergibt sich unter Java7 das folgende Array: ["", "H", "a", "l", "l", "o"]. Es ist also eine Zelle mehr als Zeichen und die erste Zelle des Arrays ist leer.
Unter Java8 ergibt sich das Array ["H", "a", "l", "l", "o"]
Encoding etc. war immer gleich.
So etwas wird doch jede Menge Kompatibilitätsprobleme geben. Bin gespannt, was da noch so alles lauert, wenn selbst eine derart grundlegende Funktion unterschiedliche Resultate erbringt.
Deshalb fährt man mit Java 6 whrs. auf der sicheren Seite. Ich bin mir auch nicht über alle Neuerungen von 7 bewusst, geschweige denn von 8. (afaik iirc imho)
Naja wer split("") verwendet hat eh einen an der Waffel. Welches EA-build verwendest du denn? Bei meinem b115 funktioniert es, also das erste Element im Array ist ein leerer String.
Gerade mit dem aktuellen Build fcs-127 probiert, da fehlt wirklich der führende Leerstring.
naja … wie gesagt : wer “String.split(”")" nutzt muss sich nicht wundern … denn split() erwratet eine RegEx … und wenn man nun mal einen String in alle seine einzelnen zeichen zerlegen will kann man das auch sauber in einer RegEx formulieren … oder macht sich den spaß und baut es mit charAt() einfach selbst …
Finde ich intuitiv auch. Ich hätte zwei leere Strings erwarte, einen vorne und einen hinten.
Beispiel:
System.out.println(Arrays.toString(splitted));```
Da kommt dann `[, a, , b]` bei raus. Der letzte leere String fehlt. Vergleiche:
```String[] splitted = ":a::b".split(":");
System.out.println(Arrays.toString(splitted));```
Dort kommt das selbe raus.
Allerdings ist das mit dem letzten leeren String dokumentiert:
> ... Trailing empty strings are therefore not included in the resulting array.
Mit b124 und b127 habe ich aber dasselbe Verhalten beim Doppelpunkt. Mit dem leeren String als Regex fehlt vorne der leere String. Das neue Verhalten ist also fehlerhaft.
Klar ist split("") nicht besonders schick und außerdem ja auch leicht anders zu lösen. Syntaktisch korrekter Code ist es aber trotzdem und er sollte keine anderen Ergebnisse erbringen als bei Java7.
Es wundert mich allerdings nicht, dass dann die Abwärtskompatibilität nicht im erwünschten Maße gegeben ist und man deshalb zwangsläufig eingebettete JRE mitgeben muss, damit es nicht zu einer Flut von Kundenanfragen bei jedem Versionswechsel kommt. Im konkreten Fall ist ja noch nicht einmal eine Drittbibliothek betroffen, sondern einfach nur plain old Java. Bei Guava war es ja ein sun.*-PAckage und da muss man sich nicht wundern. Beim Wechsel von Java6 auf Java7 hatte ich bereits so einen Nerv, da XStream den Wechsel von Sun zu Oracle nicht mitmachte.
P.S.: Das System: Win7, 32Bit JRE
java -showversion ergibt
java version “1.8.0”
Java™ SE Runtime Environment (build 1.8.0-b127)
Java HotSpot™ Client VM (build 25.0-b69, mixed mode)
Die JRE hatte ich aus dem ODN geladen als Preview.
P.P.S.: Nachtrag:
Wie sicher sind eigentlich eingebettete JREs? Sie sind ja sonst nicht im System verankert, kein Browser-Plugin etc. Gibt es Möglichkeiten diese auszunutzen? Eigentlich müsste ein Prozess ja bereits mit erhöhten Privilegien laufen (Windows) um Sicherheitslücken dort auszunutzen, oder?
Tatsächlich hat sich das Verhalten beabsichtigterweise geändert. In der Dokumentation steht ein neuer Satz:
When there is a positive-width match at the beginning of this string then an empty leading substring is included at the beginning of the resulting array. A zero-width match at the beginning however never produces such empty leading substring.
Dort ist exakt dieser Fall herausgehoben. Ein leerer String als Regex matched keinen „nichtleeren“ String, daher wird der leere führende String nicht zurückgegeben (2. Satz).
Meiner Meinung nach sollte split("") (bzw. Pattern.compile("")) eine [JAPI]PatternSyntaxException[/JAPI] werfen anstatt still schweigend ein (falsches) Ergebnis zurückzugeben, und dass schon seit Java 1.4…
Ich denke mal, diese Funktion/Methode sei gesucht:
return str.toCharArray();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
for (char c : toCharAry("Hallo")) {
System.out.print(c);
System.out.print(", ");
}
System.out.println();```
run:
H, a, l, l, o,
BUILD SUCCESSFUL (total time: 2 second)
str.split("") verwendet doch keiner (sollte), und in diesem Falle wäre str.split() (splitte bei jedem whitespace) naheliegender.
Wie TT bereits sagte, eine potentielle Quelle für Fehler (eine PSE wäre besser, aber viell. auch langsamer), denke ich mal. Aber was wäre ein JDK/JRE/IDE ohne kleinere Käfer? (Rhetorische Frage)
Es sei denn, man betrachtet das Verhalten bei Java 7 als Bug - und ich würde sagen, dass dieses Verhalten zumindest aus „principle of the least surprise“-Sicht fragwürdig ist.
Der neue Absatz in der JavaDoc lässt aber darauf schließen, dass das gewünschtes Verhalten ist: „It’s not a bug, it’s a feature.“
Und die Java 7 Version hat sich auch ihrer Dokumentation entsprechend verhalten.
[quote=cmrudolph]Und die Java 7 Version hat sich auch ihrer Dokumentation entsprechend verhalten.[/quote]Ja, nur dass der Fall eines leeren Strings als RegEx nicht erwähnt ist. Und wer sich ohne Not auf undokumentiertes Verhalten verlässt ist ggf. eben verlassen.
[QUOTE=cmrudolph]Der neue Absatz in der JavaDoc lässt aber darauf schließen, dass das gewünschtes Verhalten ist: “It’s not a bug, it’s a feature.”
Und die Java 7 Version hat sich auch ihrer Dokumentation entsprechend verhalten.[/QUOTE]
Bei Java6 und Java7 (aktuelle Versionen) entspricht das Resultat nicht der Doku (also bei Java7): Es findet sich bei beiden Versionen eine leere Zelle am Anfang des Arrays.
(Testsysteme: Win7, Java32Bit JRE und Mac OS X 10.7.3, Apple Runtime 64Bit Java6)
Doch, das entspricht der zugehörigen Doku, weil dort für einen leeren Match kein Spezialfall aufgeführt ist. Und das normale Verhalten ist, dass am Anfang auch leere Strings zurückgegeben werden, falls der Beginn der zu prüfenden Zeichenkette der Regex entspricht.