目录
概述
流是数据渠道,用于操作数据源(集合,数组等) 所生成的元素序列,集合讲究的是数据,流讲究的是计算!
- stream 自己不会存储元素
- stream 不会改变原来的数据对象,他会返回一个持有结果的信streams
- stream 操作是延迟加载的,他们会等到需要结果的时候才会需要
Stream操作的步骤
- 创建Stream: 一个数据源(集合,数组),获取一个流
- 中间操作: 对数据源的数据进行数据处理
- 终止操作: 返回一个新的需要的结果
码云地址:https://gitee.com/bufanli/java8-demo.git
创建Stream
package cn.bufanli.stream;
import cn.bufanli.pojo.Employee;
import org.junit.Test;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.Stream;
/**
* @author BuShuangLi
* @date 2019/3/11
* 一、Stream的操作步骤
* 1.创建stream
* 2.中间操作
* 3.终止操作(产生所需要的结果)
*/
public class StreamTest01 {
/**
* 创建Stream的方法
*/
@Test
public void test02() {
//1.可以通过Collection 系列集合提供的 串行流 -->Stream() 或 并行流-->parallelStream();
ArrayList<String> objects = new ArrayList<>();
Stream<String> stream = objects.stream();
//2.通过arrays 中的静态方法
Employee[] emps=new Employee[10];
Arrays.stream(emps);
//3.通过Stream类中的静态方法
Stream<String> aa = Stream.of("aa", "bb", "cc");
//创建无限流
//迭代 从0 开始进行+2操作 只需要前10个如果把limit去掉就会无限的输出
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(10).forEach(System.out::println);
//生成
Stream.generate(()->Math.random()*19).limit(5).forEach(System.out::println);
}
}
中间操作
/**
* 数据集合
*/
List<Employee> employees = Arrays.asList(
new Employee("张三", 36, 8899.99, Employee.Status.FREE),
new Employee("李四", 25, 4499.99, Employee.Status.BUSY),
new Employee("王五", 15, 5599.99, Employee.Status.VOCATION),
new Employee("王五", 15, 5599.99, Employee.Status.FREE),
new Employee("赵六", 35, 3399.99, Employee.Status.BUSY)
);
/*--------------------中间操作start--------------------*/
/**
* 中间操作
* 内部迭代:Stream API完成
* 筛选与切片
* filter--接受lambda,从流中排出某些元素
* limit--截断流,使其元素不超过指定数量
* skip(n)--跳过元素,返回一个扔掉了n个元素的流,若流中的元素不足n个,则返回一个空流,与limit互补
* distinct--筛选,通过流所生成的hashCode() 和equals() 去出重复元素
*/
@Test
public void test02() {
//filter年龄大于38取前四个
employees.stream()
//中间操作 如果没有终止操作,中间操作不会执行
.filter(employee -> employee.getAge() > 22)
//终止操作 在终止操作执行后一次性全部处理,成为惰性求值
.forEach(System.out::println);
System.out.println("-----------------");
//limit 年龄大于222 取前2个
employees.stream().filter(e -> e.getAge() > 2).limit(2).forEach(System.out::println);
System.out.println("-----------------");
//skip 年龄大于2 取前四个 跳过前两个
employees.stream().filter(e -> e.getAge() > 2).limit(4).skip(2).forEach(System.out::println);
System.out.println("-----------------");
//distinct 去重 通过hashCode() 和equals()来去重,需要重写实体的hashCode() 和equals()方法
employees.stream().filter(e -> e.getAge() > 2).limit(6).skip(2).distinct().forEach(System.out::println);
}
/**
* 映射
* map--接受lambda,将元素转换为其他形式或提取信息.接受一个函数作为参数,
* 该函数会被应用到每个元素上并将其映射成一个新的元素
* flatMap--接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流
*/
@Test
public void test03() {
List<String> strings = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
strings.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
System.out.println("-----------------");
employees.stream().map(Employee::getName).distinct().forEach(System.out::println);
System.out.println("-----------------");
Stream<Stream<Character>> streamStream = strings.stream().map(x -> getCharacterStream(x));
streamStream.forEach(s -> {
s.forEach(System.out::println);
});
System.out.println("-----------------");
//相当于上面
strings.stream().flatMap(x -> getCharacterStream(x)).forEach(System.out::println);
}
public Stream<Character> getCharacterStream(String str) {
ArrayList<Character> strings = new ArrayList<>();
for (Character c : str.toCharArray()) {
strings.add(c);
}
return strings.stream();
}
/**
* 排序
* sorted()--自然排序(Comparable)
* sorted(Comparator com)--定制排序
*/
@Test
public void test04() {
List<String> strings = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
//自然排序
strings.stream().sorted().forEach(System.out::println);
System.out.println("-----------------");
//定制排序
employees.stream().sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
终止操作
/**
* 终止操作
*/
/**
* 查找与匹配
* allMatch-检查是否匹配所有元素
* anyMatch-检查是否至少匹配一个元素
* noneMatch-检查是否没有匹配所有元素
* findFirst-返回第一个元素
* findAny-返回当前流中的任意元素
* count-返回流中元素的总个数
* max-返回流中的最大值
* min-返回流中最小值
*/
@Test
public void test05() {
//是不是匹配所有值
boolean b = employees.stream()
.allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b);
//至少匹配一个元素
boolean b1 = employees.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
//没有匹配所有元素
boolean b2 = employees.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b2);
//返回第一个元素 .sorted((eOne, eTwo) -> -Double.compare(eOne.getSalary() " - " 排序的顺序
Optional<Employee> first = employees.stream()
.sorted((eOne, eTwo) -> -Double.compare(eOne.getSalary(), eTwo.getSalary()))
.findFirst();
System.out.println(first.get());
}
@Test
public void test06(){
//count
System.out.println(employees.stream().count());
//max
Optional<Employee> max = employees.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
//min
Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compareTo);
System.out.println(min.get());
}
/**
* 归约
* reduce(T identity,BinaryOperator) /reduce(BinaryOperator) -可以将流中元素元素反复结合起来,得到一个值
*/
@Test
public void test07(){
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6, 23, 43, 66);
Integer reduce = integers
.stream()
//先把0,作为x再从流中取出一个数据为y,然后将结果最为x再从流中去....
.reduce(0, (x, y) -> x + y);
System.out.println(reduce);
//累计算出当前工资的总和 因为没有起始值
Optional<Double> reduce1 = employees.stream().map(Employee::getSalary).reduce(Double::sum);
System.out.println(reduce1.get());
}
/**
* 收集
* collect--将流转换为其他形式,接受一个Collector接口实现,用于Stream中元素做汇总的方法
*/
@Test
public void test08(){
//收集当前员工所有的名字收集然后放到集合当中
List<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toList());
collect.forEach(System.out::println);
//总和
Double sum = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max = employees.stream()
.collect(Collectors.maxBy((a, b) -> Double.compare(a.getSalary(), b.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min = employees.stream().map(Employee::getSalary)
.collect(Collectors.minBy(Double::compareTo));
System.out.println(min.get());
//分组
Map<Employee.Status, List<Employee>> group = employees.stream().collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(group);
//多几分组
Map<Employee.Status, Map<String, List<Employee>>> groups = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() >= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "青年";
} else {
return "老年";
}
})));
System.out.println(groups);
//分区 满足条件一个区,不满足条件的一个区
Map<Boolean, List<Employee>> collect1 = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 5000));
System.out.println(collect1);
//获取总和 平均 ..其他方式
DoubleSummaryStatistics collect2 = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(collect2.getAverage());
System.out.println(collect2.getCount());
System.out.println(collect2.getMax());
//.....
//连接
String collect3 = employees.stream()
.map(Employee::getName)
//[张三,李四,王五,王五,赵六]
.collect(Collectors.joining(",","[","]"));
System.out.println(collect3);
}
stream练习
实体类
package cn.bufanli.pojo;
//交易员类
public class Trader {
private String name;
private String city;
public Trader() {
}
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Trader [name=" + name + ", city=" + city + "]";
}
}
package cn.bufanli.pojo;
//交易类
public class Transaction {
private Trader trader;
private int year;
private int value;
public Transaction() {
}
public Transaction(Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader() {
return trader;
}
public void setTrader(Trader trader) {
this.trader = trader;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Transaction [trader=" + trader + ", year=" + year + ", value="
+ value + "]";
}
}
练习类
package cn.bufanli.stream;
import cn.bufanli.pojo.Employee;
import cn.bufanli.pojo.Trader;
import cn.bufanli.pojo.Transaction;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author BuShuangLi
* @date 2019/3/12
*/
public class StreamAPI {
/**
* 1.给定一个数字列表,如何返回一个由每个数的平方构成的列表,
* 给定1,2,3,4,5 返回 2,4,9,16,25
*/
@Test
public void test01() {
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
ArrayList<Integer> objects = new ArrayList<>();
List<Integer> collect = nums.stream().map(x -> x * x).collect(Collectors.toList());
System.out.println(collect);
}
/**
* 数据集合
*/
List<Employee> employees = Arrays.asList(
new Employee("张三", 36, 8899.99, Employee.Status.FREE),
new Employee("李四", 25, 4499.99, Employee.Status.BUSY),
new Employee("王五", 15, 5599.99, Employee.Status.VOCATION),
new Employee("王五", 15, 5599.99, Employee.Status.FREE),
new Employee("赵六", 35, 3399.99, Employee.Status.BUSY)
);
/**
* 怎样用map和reduce方法数一数流中有多少个Employee
*/
@Test
public void test02() {
Optional<Integer> reduce = employees.stream()
.map(e -> 1)
.reduce(Integer::sum);
System.out.println(reduce.get());
}
List<Transaction> transactions = null;
@Before
public void before() {
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
}
/**
* //1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
*/
@Test
public void test03() {
List<Transaction> collect = transactions.stream().filter(t -> t.getYear() == 2011)
.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
.collect(Collectors.toList());
System.out.println(collect);
}
/**
* //2. 交易员都在哪些不同的城市工作过?
*/
@Test
public void test04() {
List<String> collect = transactions.stream()
.map(t -> t.getTrader().getCity())
.distinct()
.collect(Collectors.toList());
System.out.println(collect);
}
/**
* //3. 查找所有来自剑桥的交易员,并按姓名排序
*/
@Test
public void test05() {
// Cambridge
List<Transaction> collect = transactions.stream()
.filter(x -> "Cambridge".equals(x.getTrader().getCity()))
.sorted((x, y) -> {
return x.getTrader().getName().compareTo(y.getTrader().getName());
}).distinct().collect(Collectors.toList());
System.out.println(collect.size());
}
/**
* //4. 返回所有交易员的姓名字符串,按字母顺序排序
*/
@Test
public void test06() {
transactions.stream()
.map(x -> x.getTrader().getName())
.sorted()
.forEach(System.out::println);
System.out.println("------------------");
String collect = transactions.stream()
.map(x -> x.getTrader().getName())
.sorted()
.collect(Collectors.joining());
System.out.println(collect);
System.out.println("------------------");
String collect1 = transactions.stream()
.flatMap(t -> filterCharacter(t.getTrader().getName()))
.sorted((x1, x2) -> x1.compareToIgnoreCase(x2)).collect(Collectors.joining());
System.out.println(collect1);
}
public Stream<String> filterCharacter(String str){
List<String> strings = new ArrayList<>();
for (Character c : str.toCharArray()) {
strings.add(c.toString());
}
return strings.stream();
}
/**
* //5. 有没有交易员是在米兰工作的?
*/
@Test
public void test07() {
boolean milan = transactions.stream().anyMatch(t -> t.getTrader().getCity().equals("Milan"));
System.out.println(milan);
}
/**
* //6. 打印生活在剑桥的交易员的所有交易额
*/
@Test
public void test08() {
transactions.stream()
.filter(x->x.getTrader().getCity().equals("Cambridge"))
.map(t->t.getValue())
.forEach(System.out::println);
}
/**
* //7. 所有交易中,最高的交易额是多少
*/
@Test
public void test09() {
Optional<Integer> max = transactions.stream()
.map(x -> x.getValue())
.max((x1, x2) -> +Double.compare(x1, x2));
System.out.println(max.get());
}
/**
* //8. 找到交易额最小的交易
*/
@Test
public void test10() {
Optional<Integer> min = transactions.stream()
.map(x -> x.getValue())
.min((x1, x2) -> +Double.compare(x1, x2));
System.out.println(min.get());
Optional<Integer> max = transactions.stream()
.map(x -> x.getValue())
.max((x1, x2) -> -Double.compare(x1, x2));
System.out.println(max.get());
}
}
并行流与顺序流
并行流就是把一个内容分成多块数据,并用不同的线程分别处理每个数据块的流
java 8 中进行了优化,我们可以很容易的数据对数据进行操作.,在数据量大的时候效率较高;
Stream API 可以声明性的通过parallel() 与 sequential() 在并行流与顺序流之间进行切换;底层是Frok/Join
package cn.bufanli.stream;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.stream.LongStream;
/**
* @author BuShuangLi
* @date 2019/3/12
*/
public class StreamParallel {
/**
* java 8 并行流
*/
@Test
public void test02() {
Instant start = Instant.now();
//顺序流
LongStream.rangeClosed(0, 100000000000L)
.reduce(0, Long::sum);
Instant end = Instant.now();
System.out.println("串行流耗时:" + Duration.between(start, end).toMillis());
//控制台打印--串行流耗时:133177
Instant start2 = Instant.now();
//并行流
LongStream.rangeClosed(0, 100000000000L)
.parallel()
.reduce(0, Long::sum);
Instant end2 = Instant.now();
System.out.println("并行行流耗时:" + Duration.between(start2, end2).toMillis());
//控制台打印--并行流耗时:73396
}
}