Strumieniowanie pozwala na iterowanie i manipulowanie elementami list i kolekcji z użyciem wyrażenia lambda.
Stream jest interfejsem generycznym, doskonałą alternatywą dla przeglądania list przy pomocy pętli i przede wszystkim jest szybsza. Pozwala też na równoległe wykonywanie operacji na danych.
Przykład:
plik Products.java
public class Products {
public String name;
public int price;
public Products(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Products{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
plik Car.java
import java.util.Comparator;
import java.util.Objects;
// w klasie musimy użyć Comparatoor do porównywania elementów, aby skutecznie stosować collect
public class Car implements Comparator<Car> {
public String name;
public int topSpeed;
public int price;
public Car(String name, int topSpeed, int price) {
this.name = name;
this.topSpeed = topSpeed;
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", topSpeed=" + topSpeed +
", price=" + price +
'}';
}
//dodajemy equals and hashcode
//wybieramy z listy tylko name
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return name.equals(car.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
//implementujemy metodę compare
//modyfikujemy zwracanie
@Override
public int compare(Car o1, Car o2) {
return o1.name.compareTo(o2.name);
}
}
plik StreamExample.java
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamExample {
public static void main(String[] args) {
//tworzymy zbiór, który następnie przefiltrujemy
ArrayList<String> arl = new ArrayList<>();
arl.add("PHP");
arl.add("Python");
arl.add("C++");
arl.add("Java");
arl.add("JS");
arl.add("HTML");
arl.add("CSS");
//aby iterować po elementach użyjemy strumieniowania zamiast pętli
//chcemy otrzymać listę elementów, których liczba znaków =3
arl.stream().filter(someValue -> someValue.length()>=3 && someValue.length()<=6)//nie dajemy średnika, bo po kropce damy kolejne metody
//możemy dodatkowo przefiltrować ze względu na literę od jakiej sie zaczybnna nazwa
.filter(someValue -> someValue.startsWith("P") || someValue.startsWith("C"))
//iterujemy po elementach po przefiltrowaniu
.forEach(someValue -> System.out.println(someValue));
//tworzymy listę na bazie klasy
ArrayList<StreamMyClass> animals = new ArrayList<>();
animals.add( new StreamMyClass("Elephant", 4000, 2));
animals.add( new StreamMyClass("Python", 150, 5));
animals.add( new StreamMyClass("ShiTzu", 7, 0));
animals.add( new StreamMyClass("Wasp", 0, 7));
animals.add( new StreamMyClass("Wife", 75, 10));
//filtrujemy elementy własnej klasy po poziomie agresji
animals.stream().filter(myName -> myName.agrresive>6)
.filter(myName -> myName.weight>50 && myName.weight<100)
.forEach(myValue -> System.out.println(myValue));
//otrzymane wyniki możemy dodać do innej kolekcji
//służy do tego metoda collect()
//tworzymy listę z wyników filtrowania
List<StreamMyClass> list = animals.stream().filter(sth -> sth.agrresive>6)
.collect(Collectors.toList());
//teraz chcemy z wyników zrobić ArrayList
ArrayList<StreamMyClass> arrl = new ArrayList<>(list);
arrl.forEach(sth -> System.out.println(sth));
//aby dodać do kolekcji tylko unikalne elementy użuwamy Set()
//przykład1
List<Integer> arr = Arrays.asList(8,-2,6,7,5,4,2,8,3,3,7,10,-11,2);
Set<Integer> uniqueNumbers = arr.stream().collect(Collectors.toSet());
System.out.println(uniqueNumbers);
//przykład2
ArrayList<String> arl1 = new ArrayList<>();
arl1.add("PHP");
arl1.add("PHP");
arl1.add("Python");
arl1.add("C++");
arl1.add("C++");
arl1.add("Java");
arl1.add("JS");
arl1.add("JS");
arl1.add("HTML");
arl1.add("CSS");
Set<String> set = arl1.stream().filter(someValue -> someValue.length()>=3 && someValue.length()<=6)
.filter(someValue -> someValue.startsWith("P") || someValue.startsWith("C"))
.collect(Collectors.toSet());
set.forEach(someValue-> System.out.println(someValue));
//przykład z użyciem klasy Car
ArrayList<Car> cars = new ArrayList<>();
//dodajmy elementy, które będą zduplikowane
cars.add(new Car("Peugeot", 270, 150000));
cars.add(new Car("Ford", 250, 170000));
cars.add(new Car("Peugeot", 270, 150000));
cars.add(new Car("Mercedes", 240,200000));
cars.add(new Car("Mercedes", 240,200000));
cars.add(new Car("MBW", 280,260000));
cars.add(new Car("Opel", 220, 140000));
//użyjemy teraz collect() do wyciągnięcia unikalnych danych
Set<Car> set1 = cars.stream().filter(car -> car.price<260000)
.collect(Collectors.toSet());
set1.forEach(car -> System.out.println(car));
//sumowanie elementów za pomoca summingToInt na bazie klasy Products
ArrayList<Products> product = new ArrayList<Products>();
//dodajmy elementy
product.add(new Products("apple", 3));
product.add(new Products("banana", 4));
product.add(new Products("pineaple", 4));
product.add(new Products("bag", 1));
product.add(new Products("perfume", 12));
int totalPrice = product.stream()
.collect(Collectors.summingInt(element -> element.price));
System.out.println(totalPrice);
//sumowanie elementów można teżprzeprowadzić za pomocą reduce()
//skorzystamy z istniejącej listy arr
int resultSum = arr.stream()
//reduce(wartość starowa, (lambda z 2 argumentami: suma dotychczasowa i następny element)
.reduce(0, (tempsum, el) -> tempsum+el);
System.out.println("wynik sumowania reduce() " + resultSum);
//sumowanie z referencją do metody
int resultSumRef = arr.stream()
.reduce(0, Integer::sum);
System.out.println("Wynik sumowania redice() z referencją: " + resultSumRef);
//zmapujmy teraz naszą listę po name
Map<String, Products> producsMap = product.stream()
.collect(Collectors.toMap(el->el.name, el->el));
System.out.println(producsMap);
//odwołajmy sie do konkretnego elementu mapy
Products pr = producsMap.get("apple");
System.out.println(pr);
//referencja do metody
List<Integer> producsPrices = product.stream()
.filter(el->el.price<10)
.map(Products::getPrice).collect(Collectors.toList());
System.out.println(producsPrices);
//kolekcję możemy przeszukać pod kątem największem i najmniejszej wartości
//max()
Products prodMaxPrices = product.stream().max((pr1, pr2) -> pr1.price>pr2.price ? 1 : -1)
.get();
System.out.println(prodMaxPrices);
//min()
Products prodMinPrices = product.stream().min((pr1, pr2) -> pr1.price>pr2.price ? 1 : -1)
.get();
System.out.println(prodMinPrices);
//ograniczmy listę zwracanych wyników, wykorzystamy istniejącą litę arr
List<Integer> result = arr.stream()
.filter(el-> el > 0 && el <10)
.limit(6)
.collect(Collectors.toList());
System.out.println(result);
//aby zliczyc ilość elementów używamy count()
System.out.println(result.stream().count());
//jeżeli potrzebujemy stworzyć stream wypełniony wartościami, możemy zrobić to dwojako
//z użyciem limit
System.out.println("Stream z limitowaniem");
Stream.iterate(0, i -> i+1).limit(10)
.forEach(stream -> System.out.print(stream));
//bez limit
System.out.println("\nStream bez limitowania");
Stream.iterate(0, i -> i<10, i -> i+1)
.forEach(stream -> System.out.print(stream));
}
}
plik StreamMyClass.java
//filtrowanie własnej klasy
//stwórzmy klasę dla klasyfikacji zwierząt pod kątem wagi i agresji
public class StreamMyClass {
public String name;
public int weight;
public int agrresive; //1-10
public StreamMyClass(String name, int weight, int agrresive) {
this.name = name;
this.weight = weight;
this.agrresive = agrresive;
}
@Override
public String toString() {
return "StreamMyClass{" +
"name='" + name + '\'' +
", weight=" + weight +
", agrresive=" + agrresive +
'}';
}
}