Java 8 – filter a map

Java 8 představila streamy a ty mají různé metody. V tomto příspěvku si ukážeme použití metod filter a map. Z původního seznamu se nejdříve vyfiltrují položky, které mají (present) status a vrátí se nový seznam, který obsahuje tyto statusy.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class App2 {

	public static void main(String[] args) {
		List<MO> list = Arrays.asList(
				new MO(Optional.of(Status.CLOSED.getId()), "AAA"),
				new MO(Optional.of(Status.OPEN.getId()), "BBB"),
				new MO(Optional.empty(), "CCC"),
				new MO(Optional.empty(), "DDD"),
				new MO(Optional.of(Status.OPEN.getId()), "EEE")
		);

		List<Long> open = list.stream()
			.filter(myObject -> myObject.getStatus().isPresent())
			.map(myObject -> myObject.getStatus().get())
			.collect(Collectors.toList());

		open.forEach(System.out::println);
	}

	private enum Status {
		OPEN(1L), CLOSED(2L);

		private long id;

		private Status(long id) {
			this.id = id;
		}

		public long getId() {
			return id;
		}
	}
}
 class MO {

	private Optional<Long> status;
	private String name;

	public MO(Optional<Long> status, String name) {
		this.status = status;
		this.name = name;
	}

	public Optional<Long> getStatus() {
		return status;
	}

	public void setStatus(Optional<Long> status) {
		this.status = status;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Výsledek:

2
1
1

Filtrování v Java 8

Java 8 představila streamy a ty mají metodu filter, která má jako parametr predikát (funkce vracejítí pravdu nebo nepravdu). V následujícím příkladu se z původního seznamu vytvoří nový seznam, který bude obsahovat pouze objekty se statusem OPEN.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class App {

	public static void main(String[] args) {
		List<MyObject> list = Arrays.asList(
				new MyObject(Status.CLOSED.getId(), "AAA"),
				new MyObject(Status.OPEN.getId(), "BBB"),
				new MyObject(Status.OPEN.getId(), "CCC"),
				new MyObject(Status.CLOSED.getId(), "DDD"),
				new MyObject(Status.OPEN.getId(), "EEE")
		);

		List<MyObject> open = list.stream()
			.filter(myObject -> myObject.getStatus() == Status.OPEN.id)
			.collect(Collectors.toList());

		open.forEach(openObject -> System.out.println(openObject.getName()));
	}

	private enum Status {
		OPEN(1L), CLOSED(2L);

		private long id;

		private Status(long id) {
			this.id = id;
		}

		public long getId() {
			return id;
		}
	}
}
 class MyObject {

	private long status;
	private String name;

	public MyObject(long status, String name) {
		this.status = status;
		this.name = name;
	}

	public long getStatus() {
		return status;
	}

	public void setStatus(long status) {
		this.status = status;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

Výsledek:

BBB
CCC
EEE

Vaadin a TextChangeListener

TextChangeListener je listener pro TextChangeEvent, která vznikne, když uživatel edituje textový obsah pole (nejčastěji psaním textu z klávesnice či vložení textu do textového pole). V následujícím příkladu vytvoříme dvě textová pole a prvnímu dáme TextChangeListener s tím, že hodnota vepsaná do prvního textového pole se změní na velká písmena a zobrazí v druhém textovém poli.

final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);

TextField tf1 = new TextField("First");
TextField tf2 = new TextField("Second");

tf1.addTextChangeListener(new TextChangeListener() {
	@Override
	public void textChange(TextChangeEvent event) {
		tf2.setValue(event.getText().toUpperCase());
	}
});

layout.addComponents(tf1, tf2);

V Javě 8 je možný tento zápis:

final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);

TextField tf1 = new TextField("First");
TextField tf2 = new TextField("Second");

tf1.addTextChangeListener(event -> {
	tf2.setValue(getValue(event.getText().toUpperCase()));
});

layout.addComponents(tf1, tf2);

Výsledek

Vaadin_a_TextChangeListener

Protocol Buffers

Protocol Buffres (protobuffers) je způsob serializace dat. Serializací je myšleno „převedení datové struktury nebo instance objektu uložené ve vnitřní paměti počítače na posloupnost bitů, kterou lze uložit na nějaké úložiště, případně přenést po síti … je třeba počítat s tím, že objekt budeme převádět zpět ze serializované do původní podoby pomocí tzv. deserializace“ (wiki: wiki).

Protocol Buffers je formát vyvinutý společností Google a je určen pro efektivní výměnu dat. Slovíčko efektivní je zde velmi důležité. Obvyklými formáty dat, pro výměnu, jsou XML a Json. Protofuffer je navržen tak, aby se dal rychle serializovat a deserializovat a byl co nejméně datově náročný. Dle stránky developers.google.com/…/overview je oproti XML:

  • jednodušší
  • 3 – 10 krát menší
  • 20 – 100 krát rychlejší
  • více jednoznačný
  • generuje datové třídy, které se jednodušeji používají.

Konkurentem protobuffers je Apačí projekt Thrift.

Protocol Buffers potřebují schéma, což je textový soubor s příponou .proto. Zde je příklad, jak takový .proto soubor může vypadat:

syntax = "proto3";

option java_package = "cz.vitfo.protobuff";
option java_outer_classname = "PbUser";

message User {
	string username = 1;
	UserProfile userProfile = 2;
}

message UserProfile {
	enum UserStatus {
		ACTIVE = 0;
		PASSIVE = 1;
		CLOSED = 2;
	}
	
	string password = 1;
	UserStatus userStatus = 2;
}

Příště si ukážeme, jak takový soubor vytvořit, zkompilovat a vysvětlíme si, co jednotlivé části znamenají.

Nastavení JAVA_HOME v Ubuntu

Proměnnou JAVA_HOME nastavíme tak, že si otevřeme soubor /etc/environment a do něj vložíme záznam:

JAVA_HOME="/usr/lib/jvm/java-8-oracle"

Soubor environment znovu načteme:

source /etc/environment

To, že naše proměnná je funkční můžeme otestovat výpisem do konzole:

echo $JAVA_HOME
/usr/lib/jvm/java-8-oracle

Zdroj: askubuntu.com/…/how-to-set-java-home-for-java

Instalace Java 8 na Ubuntu

Nejdříve je nutné přidat repozitář do souboru /etc/apt/sources.list příkazem add-apt-repository:

vitfo@vitfo-VirtualBox:/etc/opt/hbase-1.2.6$ sudo add-apt-repository ppa:webupd8team/java
[sudo] password for vitfo: 
 Oracle Java (JDK) Installer (automatically downloads and installs Oracle JDK7 / JDK8 / JDK9). There are no actual Java files in this PPA.

Important -> Why Oracle Java 7 And 6 Installers No Longer Work: http://www.webupd8.org/2017/06/why-oracle-java-7-and-6-installers-no.html

Ubuntu 16.10 Yakkety Yak is no longer supported by Canonical (and thus, Launchpad and this PPA). The PPA supports Ubuntu 17.10, 17.04, 16.04, 14.04 and 12.04.

More info (and Ubuntu installation instructions):
- for Oracle Java 7: http://www.webupd8.org/2012/01/install-oracle-java-jdk-7-in-ubuntu-via.html
- for Oracle Java 8: http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html

Debian installation instructions:
- Oracle Java 7: http://www.webupd8.org/2012/06/how-to-install-oracle-java-7-in-debian.html
- Oracle Java 8: http://www.webupd8.org/2014/03/how-to-install-oracle-java-8-in-debian.html

Oracle Java 9 (for both Ubuntu and Debian): http://www.webupd8.org/2015/02/install-oracle-java-9-in-ubuntu-linux.html

Oracle JDK 9 is now considered stable. There are currently only 64bit builds (no other builds are available for download: http://www.oracle.com/technetwork/java/javase/downloads/index.html )
 More info: https://launchpad.net/~webupd8team/+archive/ubuntu/java
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpcs1we49p/secring.gpg' created
gpg: keyring `/tmp/tmpcs1we49p/pubring.gpg' created
gpg: requesting key EEA14886 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpcs1we49p/trustdb.gpg: trustdb created
gpg: key EEA14886: public key "Launchpad VLC" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

Aktualizovat (update) informace o balíčcích příkazem apt update:

Číst dál

Zaokrouhlování v Javě pomocí BigDecimal

Pro práci s desetinnými čísly je vhodné místo double (více zde) používat BigDecimal. BigDecimal je možné nastavit scale (počet desetinných míst) a roundingMode (způsob zaokrouhlení). V příkladu je uvedeno jen několik způsobů zaokrouhlení. BigDecimal jich je možno nastavit více.

double number = 1.5555;
BigDecimal x = new BigDecimal(String.valueOf(number));
BigDecimal y = new BigDecimal(String.valueOf(number));
BigDecimal z = new BigDecimal(String.valueOf(number));

System.out.println("HALF_UP");
System.out.println(x.setScale(3, RoundingMode.HALF_UP));
System.out.println(y.setScale(2, RoundingMode.HALF_UP));
System.out.println(z.setScale(1, RoundingMode.HALF_UP));

System.out.println("HALF_DOWN");
System.out.println(x.setScale(3, RoundingMode.HALF_DOWN));
System.out.println(y.setScale(2, RoundingMode.HALF_DOWN));
System.out.println(z.setScale(1, RoundingMode.HALF_DOWN));

System.out.println("FLOOR");
System.out.println(x.setScale(3, RoundingMode.FLOOR));
System.out.println(y.setScale(2, RoundingMode.FLOOR));
System.out.println(z.setScale(1, RoundingMode.FLOOR));

System.out.println("CEILING");
System.out.println(x.setScale(3, RoundingMode.CEILING));
System.out.println(y.setScale(2, RoundingMode.CEILING));
System.out.println(z.setScale(1, RoundingMode.CEILING));

Výsledek:

HALF_UP
1.556
1.56
1.6

HALF_DOWN
1.555
1.56
1.6

FLOOR
1.555
1.55
1.5

CEILING
1.556
1.56
1.6

Zaokrouhlování v Javě pomocí knihovny Math

Knihovna Math nabízí pro zaokrouhlování tyto funkce:

  • round: vrací celé číslo (long), očekávané zaokrouhlení (od 5 nahoru)
  • rint: vrací desetinné číslo (double), podobné jakou round, ale ne vždy
  • floor: vrací desetinné číslo (double), zaokrouhluje směrem dolů
  • ceil: vrací desetinné číslo (double), zaokrouhluje směrem nahoru
double a = 1.4;
double b = 1.5;
double c = 1.6;
double na = -1.4;
double nb = -1.5;
double nc = -1.6;

System.out.println("round");
System.out.println(Math.round(a));
System.out.println(Math.round(b));
System.out.println(Math.round(c));
System.out.println(Math.round(na));
System.out.println(Math.round(nb));
System.out.println(Math.round(nc));

System.out.println("floor");
System.out.println(Math.floor(a));
System.out.println(Math.floor(b));
System.out.println(Math.floor(c));
System.out.println(Math.floor(na));
System.out.println(Math.floor(nb));
System.out.println(Math.floor(nc));

System.out.println("ceil");
System.out.println(Math.ceil(a));
System.out.println(Math.ceil(b));
System.out.println(Math.ceil(c));
System.out.println(Math.ceil(na));
System.out.println(Math.ceil(nb));
System.out.println(Math.ceil(nc));

Výsledek:

round
1
2
2
-1
-1
-2

floor
1.0
1.0
1.0
-2.0
-2.0
-2.0

ceil
2.0
2.0
2.0
-1.0
-1.0
-1.0

Vaadin a VerticalLayout

VerticalLayout má ve výchozím nastavení šířku 100% a výšku nedefinovánu (undefined). To znamená, že na šířku se roztáhne do velikosti okna prohlížeče a výška se přizpůsobí velikosti komponent, které obsahuje. Pokud je výška větší než okno prohlížeče, objeví se posuvník.

final VerticalLayout layout = new VerticalLayout();
Label l1 = new Label("Ahoj");
Label l2 = new Label("Nazdar");
Label l3 = new Label("Čau");

layout.addComponents(l1, l2, l3);

setContent(layout);

vaadin_vertical_layout_01

Pozicování komponent se provádí pomocí metody setComponentAlignment(). Tato metoda se volá až po přidání komponent do layoutu.

Číst dál

Porovnávání Optional

Při porovnávání Optional není nutné kontrolovat isPresent a volat hodnotu, ale jde rovnou porovnánat objekty.

Optional<Long> emptyLong = Optional.empty();
Optional<Long> l1 = Optional.of(1L);
Optional<String> s1 = Optional.of("abc");

System.out.println(emptyLong.equals(l1));
System.out.println(emptyLong.equals(Optional.empty()));
System.out.println(l1.equals(s1));
System.out.println(s1.equals(Optional.of("abc")));

Výsledek

false
true
false
true

Stejné to je v testech (např. při použití testNG):

assertNotEquals(emptyLong, l1);
assertEquals(emptyLong, Optional.empty());
assertNotEquals(l1, s1);
assertEquals(s1, Optional.of("abc"));

Takto asserty projdou. Pokud bychom to změnili např. na assertEquals(emptyLong, l1), dostali bychom následující chybu:

Exception in thread "main" java.lang.AssertionError: expected [Optional[1]] but found [Optional.empty]
	at org.testng.Assert.fail(Assert.java:93)
	at org.testng.Assert.failNotEquals(Assert.java:512)
	at org.testng.Assert.assertEqualsImpl(Assert.java:134)
	at org.testng.Assert.assertEquals(Assert.java:115)
	at org.testng.Assert.assertEquals(Assert.java:178)
	at ...