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:
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. |