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.

  1. 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();
}
  1. 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);
  1. 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>>>();
  1. 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);
  1. Ü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

  1. 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);
}
  1. Indeksina for tsüklis

for (var x = 1; x <= 5; x++) {
           var m = x * 2; // muidu int m = x * 2;
          System.out.println(m);
}
  1. 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);
  1. 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

  1. Meetodi parameetri tüübina

// public var demoMethod(){ return null; }
  1. Konstruktoris argumendina

// public Application(var param){ }
  1. Meetodi tagastustüübina

// public var demoMethod(){ return null; }
  1. Klassi väljana

// var firstName;
  1. catch argumendina

// try{ } catch(var ex){    }
  1. lambda sees ilma sihtmärk-andmetüüpi initsialiseerimata

// var runnable = () -> {}
  1. Arrays and Stream'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());
  1. Ü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.

  1. Dünaamiliselt andmetüüpi muutes

// var number = 10;
// number = "InfoQ";
  1. "Kokkupandult" deklareerides

// var x = 1, y = 3, z = 4;
  1. Meetodit refereerides

// var abs = BigDecimal::abs;
  1. Nulli initsialiseerides

// var name = null;
  1. 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;
  1. Kasutades mitte-lokaalse muutujana

// public var = "hello";
  1. 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;