Algoritmer og datastrukturer
Nyheter i Java 10
Nyheter i Java 10

All kode i kompendiet er laget med Java. Gjeldende versjon (sommeren 2018) er Java 10. Wikipedia har en oversikt som viser hvordan Java har utviklet seg fra versjon 1.0 som kom i 1996, til dagens versjon 10. Versjon 11 er annonsert å komme i september 2018.

Det tar vanligvis litt tid fra en ny versjon er lansert til den støttes av utviklingsverktøyene. Offisiell versjon av Java 10 kom i mars 2018. Men nå støttes den av de fleste verktøyene, f.eks. Eclipse 2018-09(v.4.9) som undertegnede bruker.

En nyhet i Java 10 er «type inference». Det er innslag av det i Java fra før, men nå kan det brukes til å definere lokale variabler av standardtyper (primitive types) og referansetyper. Det kan kalles typeinferens på norsk siden ordet inferens er i bruk. Se f.eks. NAOB (Det norske akademis ordbok). Men typeavledning hadde vært et bedre navn. Det betyr at typen til en variabel avledes av «omgivelsene» og det er nettopp det som dette handler om.

Typeinferens  En typisk variabeldefinisjon med typeinferens ser slik ut:

  1)  var x = «et typeuttrykk»;

Ordet var signaliserer at det som kommer etterpå er en variabel. I setningen 1) over heter den x. Men det er ikke oppgitt hva slags type x skal ha. Det bestemmes av det som kommer etter likhetstegnet. Der må det stå et uttrykk som har en bestemt type. F.eks. kan det være en konstant (eng: literal), en formel eller et konstruktør- eller metodekall.

I flg. eksempel brukes både den «gamle» og den nye måten til å definere en heltallsvariabel:

  2)  int a = 0;     // vanlig måte med eksplisitt typenavn
  3)  var b = 0;     // ny måte med typeinferens

I setning 2) over står det i klartekst at variabelen a skal være av typen int. Men hva med typen til b i setning 3)? Jo, også b får int som type. Det avledes av konstanten 0 siden den i Java er av typen int (32 biter). I flg. eksempler får både a, b og c int som type:

  var a = 10;                        // en konstant
  var b = (a + 7) % 4;               // en formel
  var c = Integer.parseInt("123");   // et metodekall

Dette kan også brukes i for-løkker og i for-alle-løkker (Java: enhanced for-loop):

  for (var i = 1; i <= 5; i++) System.out.print(i + " ");  // 1 2 3 4 5

Det er imidlertid ikke tillatt å bruke var i en oppramsing:

  int a = 1, b = 2, c = 3;   // tillatt kode
  var d = 1, e = 2, f = 3;   // ulovlig kode

Typeinferens kan heller ikke brukes for tabeller:

  int[] a = {1,2,3,4,5};    // a blir en int-tabell
  var b =   {1,2,3,4,5};    // ulovlig kode

Vi kan gjøre det på samme måte for typer som long, short, byte, double, float, char, boolean og String. Men vi må passe på at høyre side av likhetstegnet har ønsket type:

   4)  var a = 1L;          // a får long som type
   5)  var b = (short)2;    // b får short som type
   6)  var c = (byte)3;     // c får byte som type

   7)  var x = 3.14;        // x får double som type
   8)  var y = 3.14f;       // y får float som type

   9)  var bokstav = 'A';   // bokstav får char som type
  10)  var sann = true;     // sann får boolean som type
  11)  var navn = "Elin";   // navn får String som type

I setning 4) over kan en bruke stor eller liten bokstav, dvs. 1L eller 1l. Det er nok mest vanlig å bruke L siden l i mange fonttyper lett kan forveksles med sifferet 1. Det er ikke noen tilsvarende måte å oppgi at en tallkonstant er av typen short eller byte. Der må en, som i setningene 5) og 6), bruke vanlig typekonvertering. I setning 7) blir x en double siden en desimaltallskonstant er double. Hvis en vil ha en variabel av typen float, kan en som i setning 8), bruke en f (eller en F).

Java har som nevnt over, innslag av typeinferens fra før (før Java 10). Da typeparametre og generiske klasser ble innført, måtte en oppgi typeparameter to steder. Ta som eksempel at vi skal opprette en lenket liste med String som type:

  12)  List<String> liste = new LinkedList<String>();

I denne setningen må det være samme typeparameter begge steder. Det betyr at det er nok å opplyse om det ett sted. Dermed kan det avledes av det hva det skal være på det andre stedet. I en senere versjon av Java ble flg. kodemulighet innført:

  13)  List<String> liste = new LinkedList<>();

Diamantoperatoren   Symbolet <> fikk navnet diamantoperatoren (eng: diamond operator). Et «riktigere» navn på norsk hadde nok vært ruteoperatoren. Husk at i kortstokken heter det spar, hjerter, kløver og ruter på norsk, men spades, hearts, clubs og diamonds på engelsk. En rute er her (i kortstokken) et likesidet parallellogram på høykant og ligner på <>.

I Java 10 er det mulig å bruke typeinferens for å definere lokale variabler av referansetyper på samme måte som for standardtypene. Men hvis det er en generisk type, kan vi ikke bruke diamantoperatoren slik som i setning 13) over. Vi må gjøre det slik:

  14)  var liste = new LinkedList<String>();

Hvis en skulle glemme seg bort og ikke oppgi noen typeparameter, får en fortsatt lovlig kode:

  15)  var liste = new LinkedList<>();    // lovlig kode

Nå blir (implisitt) Object typeparameter. Det betyr at instanser av enhver referansetype kan legges inn i listen:

  var liste = new LinkedList<>();
  liste.add("Per"); liste.add(10); liste.add('A');
  System.out.println(liste);  // [Per, 10, A]

Typen til "Per" er String. Tallet 10 blir konvertert (autoboksing) til en instans av Integer og 'A' til en instans av Character.

OBS. En LinkedList kan f.eks. brukes som en stakk vha. metodene push, peek og pop, men flg. to lister fungerer litt forskjellig selv om begge er instanser av LinkedList<>:

  var liste1 = new LinkedList<String>();     // instans av LinkedList
  System.out.println(liste1.getClass());     // class java.util.LinkedList
  liste1.push("Per");

  List<String> liste2 = new LinkedList<>();  // instans av LinkedList
  System.out.println(liste2.getClass());     // class java.util.LinkedList
  liste2.push("Per");                        // ulovlig kode

Forskjellen er at liste1 er en LinkedList-referanse, mens liste2 er en List-referanse. Det betyr at referansen liste2 kun har tilgang til de metodene som grensesnittet Liste har og der ligger hverken push, peek eller pop.

Hvorfor typeinferens?  Hensikten er å få mer oversiktlig kode og kanskje også kortere kode. Det blir imidlertid interessant å se hvor mye av dette som blir tatt i bruk. Mange vil sikkert si at besparelsene blir marginale. Programmeringsmiljøene har jo allerede en del hjelpeverktøy som f.eks. kodefullføring (eng: code completion). Mange vil sikkert også si at koden blir mindre lesbar når man ikke ser i klartekst hvilken type en variabel har. Det er jo slik at «code is read much more often than it is written». Men dette er sikkert bare en vane. Råd om hvordan typeinferens bør brukes finner du på Guidelines. Det bør også nevnes at mange andre språk allerede har typeinfernes - f.eks. C++, C#, Scala, Groovy, Swift og Go.

Du finner mer informasjon om Java generelt og om de ulike versjonene under:

Til fasit  Oppgaver om Java 10
1. Sjekk at typeinferens også kan brukes i for-alle-løkker. Lag f.eks. en liste slik som i setning 14) over. Legg inn noen tegnstrenger (f.eks. navn) og skriv dem ut til konsollet vha. en for-alle-løkke.

Valid XHTML 1.0 Strict