Szerző: Forgács Ádám

Java 9 - Nyelvi újdonságok

Közeleg a Java 9 megjelenési dátuma, úgyhogy érdemes átnézni a közelgő újításokat. A legnagyobb fejlesztés a modularitás bevezetése, ami egy külön cikket érdemel és már több helyen kitárgyalásra is került. Ez a bejegyzés a kisebb, kevésbé híresztelt, de attól függetlenül hasznos újításokról tartalmaz ismertetőket. Az előző verzióhoz képest nagy nyelvi újítások nincsenek, ami érthető, hiszen a Java 8 hosszú idő után elég nagy változásokat hozott. Pár új dolog viszont bekerült, amit érdemes lehet használni.

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.

Ha tetszett a cikk oszd meg másokkal is.