try-with-resources meglévő referenciával
Eddig minden alkalommal új konstans referenciára (final vagy effectively-final) volt szükség a kezdő try blokkba. Előfordulhatott viszont olyan helyzet, hogy a bezárandó erőforrás már létezett, és ezért a try blokkban újra kellett azt definiálni. Ez többé nem szükséges. Egy jelenlegi módszer:
public ByteArrayOutputStream readContentOldWay(InputStream inputStream) throws IOException {
try (InputStream input = inputStream) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
input.transferTo(out);
return out;
}
}
Az új megoldás:
public ByteArrayOutputStream readContentNew(InputStream inputStream) throws IOException {
// inputStream = new BufferedInputStream(inputStream); // Fordítási hiba, final referencia kell
try (inputStream) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
inputStream.transferTo(out);
return out;
}
}
Nem szükséges tehát a külön referencia, viszont a meglévőnek final vagy effective final-nak kell lennie (ahogy a példában a kikommentezett sor mutatja). A példa egyébként tartalmaz egy új Java 9-es metódust is, arról azonban egy másik bejegyzésben lesz szó bővebben.
Privát metódusok interfészeken
Ez egy olyan újítás, amelyről nem sokan gondolták, hogy valaha bekerül a nyelvbe, illetve amivel kapcsolatban felmerülhet a kérdés, hogy egyáltalán mi értelme van? Egyetlen célja a default metódusok használatának megkönnyítése: ha nem szeretnénk kódot másolni, akkor egy privát metódusba elhelyezhetjük a közös részeket. Érdekesség, hogy a bájtkód szintjén már most, a 8-as verzióban támogatva vannak a privát interfész metódusok, a JVM is kezeli őket, de a hivatalos nyelvi specifikációba nem kerültek be, és így hivatalos fordítótámogatás sem volt hozzá mostanáig.
public interface Printer {
default void printObject(Object object) {
printImpl(object);
}
default void printObjects(Collection<Object> objects) {
objects.forEach(this::printImpl);
}
private void printImpl(Object obj) {
// Nem kell ismételni ezt a kódot
System.out.println("START");
System.out.println(obj);
System.out.println("END");
}
}
Természetesen az interfész metódusok alapesetben publikusak lesznek, megtartva a visszafele kompatibilitást.
Diamond operátor, absztrakt osztály megvalósításokhoz
A kifejezések jobb oldalára a Java 7 óta nem kell ismételten kiírni a típust, viszont ez eddig nem volt támogatott absztrakt osztályok esetén. Abban az egyre ritkább esetben, amikor meg kell írnunk egy implementációt (hiszen egyre népszerűbbek az interfészek, főleg a SAM típusúak), most már nem kell megismételni a típust ilyen esetben sem:
public static abstract class Request<T> {
public abstract void onSuccess(T result);
public abstract void onError(Exception e);
}
public static void handleRequest(Request<ByteBuffer> request) {
// ...
}
public static void main(String... args) {
Request<String> request = new Request<>() { // Nem kell kétszer kiírni a String típust
@Override
public void onSuccess(String result) {
System.out.println(result);
}
@Override
public void onError(Exception e) {
e.printStackTrace();
}
};
handleRequest(new Request<>() { // Típust kitalálja a fordító
@Override
public void onSuccess(ByteBuffer result) {
// ...
}
@Override
public void onError(Exception e) {
// ...
}
});
}
Természetesen a fordító kitalálja a típust metódus paraméterek esetén is, ahogyan az a handleRequest hívás esetén látszódik.
Alávonás kitiltása változónévként
Az egyedüli alávonás karakter (_) mint változónév már a Java 8-ban is figyelmeztetést dobott, mostantól fordítási hibának számít. Bár ez valószínűleg nem sok kódbázist érint. A tervek szerint később visszatérne, pl. a nem használt lambda paraméterek helyett lehetne majd alkalmazni.
public void underscore() {
// int _ = 3; // Fordítási hiba
// Predicate<String> alwaysTrue = (_) -> true; // Később (Java 10+) ez talán lehetséges lesz
}
@SafeVarargs használható privát metódusokon
Ezt az annotációt csak "nem felüldefiniálható" (final) metódusokra lehetett eddig rárakni. Mostantól lehetséges példányszintű (nem static) privát metódusokra is elhelyezni, anélkül, hogy ellátnánk őket a final kulcsszóval (hiszen azokat sem lehet felüldefiniálni). Sajnos a fordító továbbra sem veszi figyelembe osztályoknál a final kulcsszót, hiába végleges a futás során az összes metódusuk, az annotáció mégsem használható, amíg magát a metódust nem jelöljük meg a final kulcsszóval.
Ennyit a nyelvi újításokról. A következő bejegyzésben végigmegyünk az új API szolgáltatásokon is.