Vad är nytt i Java 17?

By rik

Utforska nyheterna i Java 17 LTS

Den 14 september 2021 lanserades Java 17, den senaste långsiktiga supportversionen (LTS) av Java-språket och körtidsplattformen. Låt oss undersöka de viktigaste förändringarna och avgöra om en uppgradering är motiverad.

Ett betydande antal applikationer är beroende av äldre Java-versioner, inklusive de tidigare LTS-utgåvorna Java 11 och Java 8.

Men varför skulle företag överväga att byta till den senaste Java-versionen? Att uppgradera till Java 17 kräver insatser, men det är nödvändigt för att fullt ut utnyttja de nya funktionerna i Java Virtual Machine (JVM).

Många organisationer använder Docker och Docker-avbildningar för en sömlös övergång till Java 17, vilket minimerar ansträngning och tid. Utvecklare kan definiera sina CI/CD-pipelines (Continuous Integration/Continuous Deployment) och köra dem i Docker-avbildningar. Detta påverkar inte team som använder äldre Java-versioner, eftersom de kan fortsätta använda sina befintliga Docker-avbildningar.

Nyheter i Java 17

Förbättrat stöd för macOS och AArch64

En av de viktigaste JVM-förbättringarna i den här versionen är det utökade stödet för macOS på AArch64-arkitekturen (JEP 391). Det inkluderar stöd för de senaste processorerna i M1-serien, som Apple introducerade i sina datorer det senaste året.

Även om detta kanske inte är en revolutionerande förändring för användare av dessa plattformar (vissa leverantörer har redan släppt JDK-versioner med stöd för denna arkitektur, inklusive Java 8), är det officiella stödet avgörande för att garantera framtida underhåll och support. Som jämförelse lades stöd för Linux/AArch64 till i Java 9 och Windows/AArch64 i Java 16.

Förseglade klasser

Förseglade klasser är en betydande funktion som nu är en fullvärdig del av Java-plattformen och språket i Java 17. Denna funktion ger utvecklare möjlighet att specificera exakt vilka undertyper en typ kan ha, vilket förhindrar oönskad utökning eller implementering. Detta gör det möjligt för kompilatorn att generera fel om en oförseglad typ försöker konverteras till en ogiltig undertyp.

Java 17 introducerar också en ny renderingspipeline för AWT/Swing-applikationer som körs på macOS, som använder Apple Metal API i stället för OpenGL. Dessutom ingår förbättrade API:er och funktionalitet för slumptalsgenerering.

Ändringar och begränsningar i Java 17

Java 17 medför flera förändringar, borttagningar och nya begränsningar som det är viktigt att vara medveten om.

Inkapsling av JDK Internals

Processen för inkapsling av JDK Internals är nu avslutad. Från och med Java 9 utfärdades varningar när användare försökte kringgå begränsningar och använda interna API:er via reflektion eller liknande metoder. Kommandoradsargument introducerades för att reglera detta beteende.

Sedan Java 9 har ett antal API:er utvecklats för att erbjuda ett enhetligt sätt att utföra vanliga uppgifter, med avsikten att användarna ska utnyttja dessa interna API:er. I Java 16 ändrades standardinställningen från att visa en varning till att helt avaktivera åtkomst, vilket resulterade i ett undantag. Även här kunde detta beteende ändras med ett kommandoradsargument.

Men i Java 17 har kommandoradsargumentet tagits bort och det är inte längre möjligt att avaktivera den här begränsningen. Detta betyder att all icke-auktoriserad åtkomst till dessa interna API:er nu är skyddad.

”Alltid strikt” flyttalssemantik

Man kan betrakta återinförandet av ”Always-Strict Floating Point”-semantik som en ytterligare ”borttagning”. Java 1.2 introducerade en modifiering av standardbeteendet för flyttalssemantik, som gjorde det möjligt för JVM att kompromissa med en liten mängd precision i flyttalsberäkningar för att förbättra prestandan. Nyckelordet strictfp användes för att framtvinga strikt semantik i klasser och metoder där det behövdes.

Med tiden har olika typer av instruktionsuppsättningar lagts till i processorer, vilket gör det möjligt att använda strikt flyttalssemantik utan betydande prestanda kostnader. Därmed har behovet av att implementera både standard- och strikt semantik minskat.

Java 17 tar bort den tidigare standardsemantiken och implementerar alla flyttalsoperationer strikt. Nyckelordet strictfp finns fortfarande kvar, men det har ingen praktisk effekt och genererar en kompileringsvarning.

Ahead-of-Time (AOT) kompilering

Java 9 introducerade experimentell AOT-kompilering, som använder Graal-kompilatorn, där JIT-koden skrevs med Java. I Java 10 införlivades Graal-kompilatorn som en JIT-kompilator i OpenJDK via JVMCI-gränssnittet. Sedan lanseringen har det blivit betydande förbättringar, och Graal-kompilatorn har utvecklats till GraalVM med sin egen JVM.

RMI-aktivering

RMI-aktivering, som togs bort från Java 8, har nu eliminerats i JEP 407, och ansågs vara en nödvändighet för borttagning i Java 15. RMI-aktivering tillhandahöll en metod för att aktivera distribuerade objekt på begäran med RMI. Användningen av RMI-aktivering var dock minimal, och det finns idag bättre alternativ. Elimineringen av aktiveringsdelen påverkar inte resten av RMI.

Borttagning av Applet API

Applet API har slutligen avskaffats i JEP 398, efter att ursprungligen ha tagits bort i Java 9. Applet API tillät integrering av Java AWT/Swing-kontroller i webbsidor. Eftersom inga moderna webbläsare har stöd för detta, har applets i princip varit otillgängliga det senaste decenniet.

Security Manager

Den viktigaste borttagningen är Security Manager (JEP 411). Security Manager har funnits sedan Java 1.0 och var utformat för att begränsa Javas lokala möjligheter, som begränsa åtkomst till nätverk, filer och andra resurser. Den försöker också ”sandlåda” icke-betrodd kod genom att blockera reflektion och vissa API:er.

Avvecklingen av Security Manager började i Java 12, då ett kommandoradsargument lades till för att blockera användningen av Security Manager vid körtid. Ändringen i Java 17 innebär att en körningsvarning utfärdas i JVM när man försöker ställa in en Security Manager, oavsett om det sker via kommandoraden eller dynamiskt under körtid.

Inkubator- och förhandsfunktioner

Med tanke på att Java 17 marknadsförs som en LTS-version, fanns det många spekulationer kring huruvida den skulle inkludera förhandsgransknings- eller inkubatorfunktioner. Java 17 inkluderar faktiskt två inkubatormoduler och en förhandsfunktion.

Vektor-API

Vektor-API:et (JEP 414) är för närvarande i sin andra inkubationsfas. Det här API:et ger utvecklare möjligheten att definiera vektorberäkningar som JIT-kompilatorn konverterar till lämpliga vektorinstruktioner som stöds av den aktuella CPU-arkitekturen, t.ex. genom att använda instruktionsuppsättningarna SSE eller AVX.

Tidigare var utvecklare tvungna att förlita sig på skalära funktioner eller skapa plattformsspecifika inbyggda bibliotek. Implementeringen av Vektor-API:et i Java ger också en sömlös fallback-mekanism, som var mer komplicerad i tidigare versioner.

Standardiseringen av Vektor-API:et möjliggör för klasser i JDK att utnyttja det. Till exempel kan metoderna i Java Arrays mismatch() ändras för att köras i Java istället, vilket eliminerar behovet av att underhålla och skriva flera plattformsspecifika implementeringar inom JVM.

Foreign Function & Memory API

En annan inkubatorfunktion är Foreign Function & Memory API (JEP 412). Detta API är en utveckling och sammanslagning av två andra inkubatormoduler från Java 16: Foreign Linker API (JEP 389) och Foreign-Memory API (JEP 393). Båda ger tillgång till inbyggt minne och kod via statiskt typad programmering skriven i Java.

Mönstermatchning för Switch

Den sista förhandsfunktionen i Java 17 är Pattern Matching for Switch (JEP 406). Denna funktion utökar switch-uttryck och -satser med typbaserad matchning, som liknar syntaxen för Pattern Matching (JEP 394), som blev en standardfunktion i Java 16.

Tidigare, om du ville utföra olika åtgärder baserat på ett objekts dynamiska natur, var du tvungen att skapa en ”if-else”-kedja med hjälp av ”instanceof”-kontroller, till exempel så här:

String type(Object o) {
  if (o instanceof List) {
    return "En lista med saker.";
  }
  else if (o instanceof Map) {
    return "En Map! Den har nycklar och värden.";
  }
  else if (o instanceof String) {
    return "Detta är en sträng.";
  }
  else {
    return "Detta är något annat.";
  }
}

Genom att kombinera switch-uttrycket med den nya mönstermatchningsfunktionen för switchar kan processen förenklas till något liknande följande:

String type(Object o) {
  return switch (o) {
    case List l -> "En lista med saker.";
    case Map m -> "En Map! Den har nycklar och värden.";
    case String s -> "Detta är en sträng.";
    default -> "Detta är något annat.";
  };
}

Som du kanske har märkt gör deklarationen av en variabel det möjligt att typsäkra objektet under kontrollen. Det samma gäller för andra variabler i mönstermatchningen. Den här funktionen indikerar att objektets typ kontrolleras, castas och är tillgänglig från variabeln inom sitt aktuella område.

Den här förhandsfunktionen är ytterligare ett steg mot komplett mönstermatchning. Nästa steg är att införa möjligheten att dekonstruera arrayer och poster.

Ska du uppgradera till Java 17?

Det är viktigt att hålla sig uppdaterad med de senaste versionerna, men det är inte nödvändigt att uppgradera omedelbart vid lanseringen. Programvaran och biblioteken du använder kanske ännu inte är kompatibla med Java 17, så det kan vara klokt att vänta lite.

Om du är beroende av en LTS-version, som Java 8 eller Java 11, så finns det en rad förbättringar både inom språket och JVM:en som motiverar en uppgradering till Java 17. Dess status som en LTS-version gör det sannolikt att även din produktionsmiljö så småningom kommer att uppdateras till Java 17.

Om du startar ett nytt projekt eller om du är på väg att göra projektet redo för Java 17, är det förmodligen bäst att byta till Java 17 förr snarare än senare, eftersom detta kommer att minska kostnaderna för migrationen. Det ger också utvecklarna möjlighet att utnyttja de senaste funktionerna.

Du kan dra nytta av de många förbättringar som gjorts under de senaste åren, såsom förbättrat stöd för containers i Java samt de nya implementeringarna av skräpsamlare med låg latens.