var andmetüüp
Var
on andmetüüp, millega saab deklareerida muutujat ilma muutuja andmetüüpi ise täpsustamata. Kui deklareerimine (vasakul võrdusmärgist) ja initsialiseerimine (paremal võrdusmärgist) toimub samal real, suudab Java kompileerija andmetüüpi järeldada.
var age = 10; // järeldatakse, et andmetüüp on int
kuna var
ei ole keyword
vaid andmetüüp nagu String
või int
ehk täiesti legaalne on
var var = 10;
Javas toimub andmetüübide määramine kompileerimisajal (st. enne programmi käivitamist, programmeerija kirjutatud koodi bait-koodiks tõlkimise käigus), mitte dünaamiliselt programmi töö ajal (runtime
). Seetõttu genereeritud bait-kood on sama nii eraldi andmetüüpi täpsustades kui ka var
kasutamise korral.
var kasutuse eelised
var
kasutamine võib kas parandada koodi loetavust, kõrvaldades üleliigse teabe või halvendada koodi loetavust, eemaldades kasuliku teabe.
Keskendumine muutuja nimele, muutuja andmetüübi asemel.
try (InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is, charsetName);
BufferedReader buf = new BufferedReader(isr)) {
return buf.readLine();
}
// asemel
try (var inputStream = socket.getInputStream();
var reader = new InputStreamReader(inputStream, charsetName);
var bufReader = new BufferedReader(reader)) {
return bufReader.readLine();
}
Müra vähendamine väikese kasutusalaga (skoopiga) muutujate korral. Näiteks vaid korra kasutuses olevate muutujate puhul.
String message = "Hello world!";
Path path = Path.of("debug.log");
InputStream stream = Files.newInputStream(path);
// asemel
var message = "Hello world!";
var path = Path.of("debug.log");
var stream = Files.newInputStream(path);
Müra vähendamine genereeriliste andmetüüpidega.
PS! var
'iga genereerilisi tüüpe inistsialiseerides ei saa tugineda ainult liidesele – teemantsulgudes peab täpsustama konkreetset andmetüüpi.
Map<String, List<Map.Entry<String, Integer>>> map = new HashMap<>();
// asemel
var map = new HashMap<String, List<Map.Entry<String, Integer>>>();
Kergemini mõistetavamad muutujate nimetamised aheldatud ("chained") ja pesastatute ("nested") toimingutes.
return strings.stream()
.collect(groupingBy(s -> s, counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey);
Enne kui saame var
andmetüüpi kasutada peame stream
'i avama lokaalsete muutujatega.
Map<String, Long> freqMap = strings.stream().collect(groupingBy(s -> s, counting()));
Optional<Map.Entry<String, Long>> maxEntryOpt = freqMap.entrySet().stream().max(Map.Entry.comparingByValue());
return maxEntryOpt.map(Map.Entry::getKey);
ning siis saame kasutada var
lokaalsete andmetüüpide deklareerimise asemel
var freqMap = strings.stream()
.collect(groupingBy(s -> s, counting()));
var maxEntryOpt = freqMap.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
return maxEntryOpt.map(Map.Entry::getKey);
Ületäpsustava ("boilerplate") koodi vältimine
Collections
'ite puhl.
List<String> list = Arrays.asList("One", "Two", "Three", "Four", "Five");
// asemel
var list = Arrays.asList("One", "Two", "Three", "Four", "Five");
Kasutusjuhud
for-each
tsüklis
var list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
for (var item : list) {
var m = item + 2;
System.out.println(m);
}
Indeksina
for
tsüklis
for (var x = 1; x <= 5; x++) {
var m = x * 2; // muidu int m = x * 2;
System.out.println(m);
}
stream
'is
var list = List.of(1, 2, 3, 4, 5, 6, 7);
var stream = list.stream();
stream.filter(x -> x % 2 == 0).forEach(System.out::println);
Kolmekordse
ternary
operaatoriga
var z = 1 > 0 ? 10 : -10;
// võib ka erinevate andmetüüpidega ternary’s kasutada
var x = 1 > 0 ? 10 : "Integer if 1 > 0"; System.out.println(x.getClass());
var y= 1 < 0 ? 10 : "String if 1 < 0"; System.out.println(y.getClass());
Kus mitte kasutada
Meetodi parameetri tüübina
// public var demoMethod(){ return null; }
Konstruktoris argumendina
// public Application(var param){ }
Meetodi tagastustüübina
// public var demoMethod(){ return null; }
Klassi väljana
// var firstName;
catch
argumendina
// try{ } catch(var ex){ }
lambda
sees ilma sihtmärk-andmetüüpi initsialiseerimata
// var runnable = () -> {}
Arrays
andStream
'is ilma andmetüüpi täpsustamata
private <T extends Number> List<Integer> toIntgerList(List<T> numbers) {
var integers = numbers.stream()
.map(Number::intValue)
.collect(Collectors.toList());
return integers;
}
public void main(String[] args) {
// var numbers = List.of(1.1, 2.2, 3.3, 4.4, 5.5);
// var integers = toIntgerList(numbers);
// System.out.println(integers);
}
selle asemel tee
private List<Integer> toIntgerList(List<Double> numbers) {
List<Integer> integers = numbers.stream()
.map(Number::intValue)
.collect(Collectors.toList());
return integers;
}
public void main(String[] args) {
List<Double> numbers = List.of(1.1, 2.2, 3.3, 4.4, 5.5);
List<Integer> integers = toIntgerList(numbers);
System.out.println(integers);
}
var list = List.of("apple", "banana", "cherry"); var uppercaseList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
Ülemklassi andmetüübi muutes alamklassi andmetüübiks
var password = new JPasswordField("Password text");
var textField = new JTextField("Hello text");
// password = textField;
muidu täiesti lubatud on alamklassi andmetüübi ülemklassi omaks muutmine textField = password
.
Dünaamiliselt andmetüüpi muutes
// var number = 10;
// number = "InfoQ";
"Kokkupandult" deklareerides
// var x = 1, y = 3, z = 4;
Meetodit refereerides
// var abs = BigDecimal::abs;
Nulli initsialiseerides
// var name = null;
Massiivi deklareerides
// var numbers = {2, 4, 6};
// var numbers[] = {2, 4, 6};
// var[] arr = new int[10];
Initsialiseeri massiivi hoopis nii
var numbers = new int[]{2, 4, 6};
var arr = new int[10];
var number = numbers[1];
number = number + 3;
Kasutades mitte-lokaalse muutujana
// public var = "hello";
Kui initsialiseerimine võib muuta andmetüüpi
// ORIGINAL
byte flags = 0;
short mask = 0x7fff;
long base = 17;
// DANGEROUS: kõiki määratakse int andmetüüpideks
var flags = 0;
var mask = 0x7fff;
var base = 17;