Project Coin features in Java 7
-
Upload
jan-krag -
Category
Technology
-
view
143 -
download
5
Transcript of Project Coin features in Java 7
Project Coin features i Java 7
Jan Krag
14. Juni 2013
For Udvikling 1
Project Coin
Projekt til forbedring af Java sproget http://openjdk.java.net/projects/coin/
Delt op mod hhv. Java 7 og Java 8
Målsætninger: Gøre java kode mere læsbar
Opfordre til at skrive mere pålidelig kode
velintegreret med både tidligere og fremtidigesprogændringer
Færre tastetryk, renere kode, gladereudviklere
Begrænsninger
INGEN ændringer I JVM’en
Koordineret med kommende Java 8/9 ændringer
Forholdsvis små sprogændringer
Dvs. “små” med henblik på:
ændringer til language spec.
Implementering
Refac af eksisterende libraries
Test
Overblik: the 7-4-7
1. Improved literals
2. Strings in switch
3. Try-with-resources
4. Multicatch
5. Precise rethrow
6. Diamond operator
7. Safe Varargs
1a) Binary literals
Nu kan man også specificere konstanter
I binær form:
byte b = 0b01001101;
1b) Underscores in literals
Den “lille forskel”
Det er nu lovligt at sætte (vilkårligt
mange) underscores mellem “cifre” in
talkonstanter
Kun med formål at gøre koden mere
læsbar.
Ingen konsekvenser efter compile
Eksempel
long creditCardNumber =
1234567890123456L;
long bytes =
0b11010010011010011001010010010010;
Kan nu skrives som:
long creditCardNumber =
1234_5678_9012_3456L;
long bytes =
0b11010010_01101001_10010100_10010010;
long hexWords = 0xCAFE_BABE;
int ok = 5_______2;
Men ikke alt er lovligt:
float pi1 = 3_.1415F;
float pi2 = 3._1415F;
long s = 999_99_9999_L;
int x3 = 52_;
int x6 = 0x_52;
int x5 = 0_x52;
int x1 = _52; // lovligt, men er et variabel navn, ikke en talkostant
// Courtesy Josh Bloch
int bond =
0000_____________0000________0000000000000000__000000000000000000+
00000000_________00000000______000000000000000__0000000000000000000+
000____000_______000____000_____000_______0000__00______0+
000______000_____000______000_____________0000___00______0+
0000______0000___0000______0000___________0000_____0_____0+
0000______0000___0000______0000__________0000___________0+
0000______0000___0000______0000_________000+__0000000000+
0000______0000___0000______0000________0000+
000______000_____000______000________0000+
000____000_______000____000_______00000+
00000000_________00000000_______0000000+
0000_____________0000________000000007;
2) Strings in switch
int monthNameToDays(String s, int year) {
switch(s) {case "April":
case "June":
case "September":
case "November":
return 30;
case "January":
case "March":
case "May":
case "July":
case "August":
case "December":
return 31;
case "February":
return 31;
default: ...
}
Strings in switch
Tilføjet kun 1 ord i JLS!
Implementeret med “desugaring” instedet for JVM ændring!
Dvs. koden reduceres pre-compile til en form der allerede er understøttet
Bruger en switch på String.hashCode (ogequality checks ved hash collision) til at oversætte til int’s, og derefter bare en intswitch.
… perfomer derved klart bedre end en langrække equality checks på strenge
Ulempe???
Risiko: Kan friste udviklere til at
misbruge Strings til kode hvor rigtige
type-stærke datatyper ville være bedre
(ofte Enums)
3) Try with resources
Stort problem med nuværende måde at
sikre lukning af åbne resourcer.
Åbning af resourcer kan smide exceptions,
og skal derfor I try-catch.
Lukning af resourcer kan smide exceptions
og derfor skal der ny try-catch I finally osv.
Går helt galt med de typiske chainede
resourcer (input stream etc.), hvor der er
flere lag der kan smide exceptions
Du tror måske…
… at du kan skrive koden “rigtig” men…
Da man i forbindelse med den nye feature
(tålmodighed please) analyserede de
eksisterende Java standard libraries, fandt
man ud af at koden var “forkert” I 66% af
alle tilfælde, så selv dem der har skrevet
JDK’en har ikke kunnet finde ud af at gøre
koden vandtæt.
public static void main(String[] args) {
BufferedReader br = null;
try {
String line;
br = new BufferedReader(
new FileReader("C:\\testing.txt")
);
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Ny version:
public static void main(String[] args) {
try (
BufferedReader br =
new BufferedReader(
new FileReader("C:\\testing.txt")))
{
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
try(assignment; assignment; …)
Alle resourcer bliver automatisk lukket eftertry-blokken
Men: der var en del “skjulte” detaljer der skulle håndteres:
Der kan nu genereres flere exceptions I blokken, og vi vil ikke “miste” de underliggende helt
null- håndtering (forsøg på close afresource initialiseret til null)
Try with resources -
implementering
Nyt interface: java.lang.AutoCloseable,
indsat I hieraki over java.io.Closable
Ny feature Throwable.addSuppressed
Taget I brug I den eksisterende JDK
Bl.a. også I JDBC 4.1
Også implementeret med “desugaring”
instedet for JVM ændring!
Desugar
try ResourceSpecification
Block
… bliver til{
final VariableModifiers_minus_final R #resource = Expression;
Throwable #primaryException = null;
try ResourceSpecification
Block
catch (Throwable #t) {
#primaryException = t;
throw #t;
} finally {
if (#resource != null) {
if (#primaryException != null) {
try {
#resource.close();
} catch(Throwable #suppressedException) {
#primaryException.addSuppressed(#suppressedException);
}
} else {
#resource.close();
}
}
}
}
4) Multicatch – kort fortalt
static <T> T instantiate(Class<? extends T> cl) {
try {
return cl.newInstance();
} catch (
IllegalAccessException | InstantiationException leeloo) {
throw new IllegalArgumentException(leeloo);
}
}
Multicatch
Sparer en masse kode-duplikering
(DRY)
Giver faktisk lidt bedre performance, da
det oversættes (af javac) til én entry i
exception tabellen istedet for 4
Multicatch - detaljer
Kræver i princippet at Exception
variablen er final (jvm detaljer), men det
håndteres nu af compileren med ny
“effectively final” analyse
Hvad med:
catch(Foo | SonOfFoo e) {...}
p.t. specifikt forbudt i JDK 7
Men kan sagtens tilføjes senere
5) Precise rethrow
try {
// Reflection operationer som f.eks.
//Class.forName, Class.newInstance,
} catch(
ClassNotFoundException | InstantiationException |
NoSuchMethodException | InvocationTargetException e) {
log(e);
throw e;
}
Eller uden multicatch:
… catch(Exception e) {
log(e);
throw(e);
}
Precise rethrow
… hvad er så typen af den Exception der
kastes i throw(e)?
I JDK <7 er det altid typen af variablen
e, dvs. I praksis “Exception”, og det er jo
problematisk og upraktisk når e ikke kan
være andet end det try-blokken rent
faktisk kan smide.
Rethrow I JDK 7 og frem
Nu kan compileren holde styr på hvilken
type ens Exception rent faktisk kan
have, og derfor smides en “sammensat
type” af de exceptions der er på tale.
Denne sammensatte type kan ikke
“udtrykkes” i kode, (så derfor er der
stadig udfordringer hvis Exc. skal
“gemmes” og smides andetsteds f.eks. i
en anden tråd)
Precise rethrow - konklusion
I praksis en meget brugbar feature med meget få ulemper.
Men: ikke helt bagudkompatibel…try {
throw new DaughterOfFoo();
} catch (Foo e) {
try {
throw e;
// Pre-JDK 7 smides Foo,
// nu smides DaughterOfFoo
} catch (SonOfFoo e2) {
; // Kan denne kode nås?
}
}
6) Diamonds (are a girls coders best
friend)
Vi skriver ofte ting som:Map<Integer, Map<String, String>> usersMaps = new HashMap<Integer, Map<String, String>>();
Aaargh!!!
Nu kan vi “bare” skrive:Map<Integer, Map<String, String>> usersMaps = new HashMap<>();
<> kaldes “Diamond” operatoren
Diamond - fortsat
Laver rigtig “type inference”, ikke bare
streng-substitution
Note: Modsat af mange andre sprog
(f.eks. Scala og .Net)
andre sprog laver inferens på variablen
(venstre side): val a = new String(“asd”)
Java 7 laver inferens på værdi-siden (højre),
dvs. Vi specificerer variablens type, og
gætter typen på det objekt der tildeles.
Diamond - detaljer
Det viste sig at være en relativt
kompleks ændring at indføre, med
mange non-trivielle designbeslutninger
Flere mulige inferens algoritmer blev
overvejet, 2 var “lige gode” (ordnede
hver sine 90%).
problemer med anonyme indre klasser:
Diamond – Et eksempel på problem
Object o;
List<?> arg = ...;
o = new Box<>(arg);
Bliver til:
Object o;
List<?> arg = ...;
o = new Box<List<captureof?>>(arg);
OK, Men hvad så med:
o = new Box<List<captureof ?>>(arg){...};
Laves til en ny klasse:
o = new a$1(arg);
class a$1 extends Box<List<captureof ?>>{...}
Men denne klasses skal indeholde spec af sin superklassestype-descriptor som ikke kan udtrykkes I class-filen.
Derfor ikke lovligt i java 7!
public class Box<T> { private T value;
public Box(T value){ this.value = value;
}
T getValue() { return value;
}
}
7) Safe Varargs
Problem idag (JDK < 7) med “unchecked” warnings ved kald af library metoder der tager varargs.
Skyldes at varargs er impl. som arrays, ogarrays ikke understøtter generics pga. covariant typehierarki (kort: String[] kanassignes til Object[] og resultere I runtime CCE hvis man hiver en forkert type ud)
Warnings kommer på call-site og derforsvære at “fjerne”
Varargs - løsning
@SafeVarargs annotation
Men:
Erklærer kun at koden opfører sig “pænt”
Forhindrer egentlig ikke runtime CCE
Kan kun bruges på static og final metoder
da annotations ikke nedarves.
Fremtidig java-version vil forhåbentligt
få compile-time checks
… mulige Coin forbedringer i JDK 8
Try-with-resources på “effectively final”
variable
Dvs. man ikke behøver at assigne til en ny
variabel i try(…)
Fjerne nogle begrænsninger på
Diamond
Måske @SafeVarargs på private
metoder?
… der var dog mere i JDK 7
NIO.2 – New I/O version 2
Method handles
invokeDynamic (ny bytecode instruktion)
Forbedret concurrency
Forbedret Unicode
Diverse andre småting (f.eks. Objects.deepEquals helper)
Her må være flere gode idéer til fremtidige emner(kom frit frem)
… og så er der jo hele JDK 8 !