Java 8中两大最重要的改动就是 Lambda表达式 和 Stream API。Stream是java 8中处理集合的关键抽象概念。集合讲的是数据,流讲的是计算。
Stream操作包含3个重要步骤,分别是创建Stream,中间操作,终止操作。
文章积累:https://www.cnblogs.com/lucky_dai/p/5485421.html
1. 创建Stream流
创建Stream包含三种常用方法:
(1) java.util.Collection接口提供了2个方法stream()和parallelStream()可以创建Stream流。
(2) Arrays的静态的方法stream()也可以获取数据流。
(3) Stream.of() 方法可以通过显示值创建流。
(4) 由函数创建流,无限流。可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
下面代码演示4种生成stream的方法:
@Test
public void test(){
/**
1. Collections(实现了Collections接口的类) 的 stream()方法
和 parallelStream() 方法获取。
*/
List<String> lis = new ArrayList<>();
lis.add("Lucas");
lis.add("Alice");
lis.add("Jim");
lis.add("Zeus");
Stream<String> sl = lis.parallelStream();
sl.forEach(System.out::println);
/**
* 2. 通过Arrays中的静态方法获取数组流
*/
Employee[] emp = new Employee[]{
new Employee("Joe",28000,31),
new Employee("Lucy",5000,18),
new Employee("Robin",400,7),
new Employee("Cristina",40000,35),
new Employee("Fancy",18000,55),
new Employee("Lion",4000,26)
};
Stream<Employee> estr = Arrays.stream(emp);
estr.forEach(System.out::println);
/**
* 3.通过Stream类的静态方法of获取数据流
*
* public static<T> Stream<T> of(T... values) {
* return Arrays.stream(values);
* }
* T... 可变长参数,就是这个位置可以传入任意个该类型参数,简单来说就是个数组。
*
*/
Stream<Integer> estr1 = Stream.of(new Integer[]{5,6,7,2,1,9});
estr1.forEach(System.out::println);
/**
* 4.由函数创建流,无限流。
* 可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
*
* seed是种子,也就是初始值,后边UnaryOperator是一个Function函数式接口。
* public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
*
* public static<T> Stream<T> generate(Supplier<T> s)
*/
Stream<Integer> si = Stream.iterate(0,x->x+2);
si.limit(10).forEach(System.out::println);
Stream si1 = Stream.generate(()->89);
si1.limit(10).forEach(System.out::println);
}
2. Stream中间操作
Stream中间可以经过多个类似“流水线”式的操作,除非执行了最后的终止操作,否则不会触发计算生成最后结果(这点和Spark和Flink的中间算子是类似的),也叫做惰性计算。
中间操作还可以分为几类:
2.1. 筛选和切片:
筛选和切片主要介绍4个方法,分别是: filter,distinct,limit,skip。
四个方法都在接口中有定义,分别是:
Stream<T> filter(Predicate<? super T> predicate);
Stream<T> limit(long maxSize);
Stream<T> distinct();
Stream<T> skip(long n);
前1,3个方法很好理解,主要介绍下第2,4个:
skip: 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补。
distinct:筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
@Test
public void test02(){
/**
* 筛选和切片: filter,distinct,limit,skip;
*
* Stream<T> filter(Predicate<? super T> predicate);
* Stream<T> limit(long maxSize);
* Stream<T> distinct();
* Stream<T> skip(long n);
* skip: 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n)互补
*
* 内部迭代,迭代工作由Stream API完成。
*/
//获取到流
Stream<Employee> se = Arrays.stream(emp);
se.filter((e)->e.getSalary()>10000) //筛选大于10000工资的emp
.limit(3)
.distinct()
.forEach(System.out::println);
System.out.println("---------------------------------------------");
//获取到流
Stream<Employee> se1 = Arrays.stream(emp);
se1.skip(2)
.forEach(System.out::println);
}
2.2. 映射:
映射主要包含map和flatMap。
Map: 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap: 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
public static Stream<Character> str2CharStream(String str){
List<Character> li = new ArrayList<>();
for(Character ch : str.toCharArray()){
li.add(ch);
}
return li.stream();
}
@Test
public void test03(){
/**
* 映射操作
* map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
* <R> Stream<R> map(Function<? super T, ? extends R> mapper);
* <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
*
* flatMap将每一个字符串拆分成一个Character Stream后,再将所有的字符,串成一个大的字符Stream。
*/
Integer[] sers = new Integer[]{9,8,3,2,1,34,76};
Stream<Integer> st1 = Arrays.stream(sers);
st1.map(x -> x+20)
.map(x -> x+".3")
.map(x -> Double.valueOf(x))
.forEach(System.out::println);
String[] sers1 = new String[]{"Alice","Bob","Christina","Rose","Peak"};
Stream<String> st2 = Arrays.stream(sers1);
Stream<Character> ssc = st2.flatMap(StreamAPI::str2CharStream);
ssc.forEach(System.out::println);
}
3. Stream API的练习:
针对上边的API内容,设计了下边的实验方法。题目的说明在代码中有显示。
Trader.java
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 + "]";
}
}
Transaction.java
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 + "]";
}
}
StreamTest.java
public class StreamTest {
/**
* 1. 给定一个数字列表,返回每个数字的平方组成的列表,例如输入 1,3,7,8 返回 1,9,49,64
* @param input_list 一个数字列表
* @return 数字的平方组成的列表
*/
public List<Integer> squareCal(List<Integer> input_list){
Stream<Integer> st_in = input_list.stream();
List<Integer> out_list =
st_in.map(x -> x*x)
.collect(Collectors.toList());
return out_list;
}
/**
* 2.使用map 和reduce方法 数一数流中有多少个Employee
* @param emp Employee对象列表
* @return
*/
public int CountEmp(List<Employee> emp){
return emp.stream()
.map(e -> 1)
.reduce(0,(x,y ) -> x+y);
}
/**
* 3. 使用基础类Trader, Transaction ,并使用Stream完成如下一些需求:
* 1) 找出2011年发生的所有交易,并按照交易额排序(从低到高)
* 2) 交易员都在哪些不同的城市工作过。
* 3) 查找所有来自剑桥的交易员,并按照名字排序。
* 4)返回所有交易员的姓名字符串,按字母排序。
* 5) 打印生活在剑桥的交易员的交易额
* 6)所有的交易中,最高的交易额是多少
* 7)找到交易额最小的交易
* 8)有没有在米兰工作的交易员。
* */
public void transactionTest(){
//初始化基础测试数据
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
List<Transaction> 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)
);
System.out.println(" --------------------找出2011年发生的所有交易,并按照交易额排序(从低到高)--------------------");
transactions.stream()
.filter(t -> t.getYear() == 2011)
.sorted((x,y) ->Integer.compare(x.getValue(),y.getValue()))
.forEach(System.out::println);
System.out.println(" --------------------交易员都在哪些不同的城市工作过--------------------");
transactions.stream()
.map(x ->x.getTrader().getCity())
.distinct()
.forEach(System.out::println);
System.out.println(" --------------------查找所有来自剑桥的交易员,并按照名字排序--------------------");
transactions.stream()
.filter(x ->x.getTrader().getCity().equals("Cambridge"))
.map(x -> x.getTrader() )
.sorted((x,y) -> x.getName().compareTo(y.getName()))
.distinct()
.forEach(System.out::println);
System.out.println(" --------------------返回所有交易员的姓名字符串,按字母排序--------------------");
transactions.stream()
.map(x -> x.getTrader().getName())
.sorted((x,y) -> x.compareTo(y))
.forEach(System.out::println);
System.out.println(" --------------------打印生活在剑桥的交易员的交易额--------------------");
transactions.stream()
.filter(x -> x.getTrader().getCity().equals("Cambridge"))
.map(x -> x.getValue())
.forEach(System.out::println);
System.out.println(" --------------------所有的交易中,最高的交易额是多少--------------------");
Optional<Integer> max_value = transactions.stream()
.max((x,y) -> Integer.compare(x.getValue(),y.getValue()))
.map(x -> x.getValue());
System.out.println(max_value.get());
System.out.println(" --------------------找到交易额最小的交易--------------------");
Optional<Transaction> min_trans = transactions.stream()
.min((x,y) -> Integer.compare(x.getValue(),y.getValue()))
;
System.out.println(min_trans.get());
System.out.println(" --------------------有没有在米兰工作的交易员--------------------");
boolean Milan_exi = transactions.stream()
.map(x -> x.getTrader())
.anyMatch(x -> x.getCity().equals("Milan"));
System.out.println(Milan_exi);
}
public static void main(String[] args) {
StreamTest st_ob = new StreamTest();
// 问题1 测试
List<Integer> list = Arrays.asList(4,8,2,199,5,37);
System.out.println(Arrays.toString(st_ob.squareCal(list).toArray()));
//问题2 测试
List<Employee> emp_list = Arrays.asList(
new Employee("Joe",28000,31),
new Employee("Denny",5000,36),
new Employee("Lucy",5000,18),
new Employee("Robin",400,7),
new Employee("Cristina",40000,35),
new Employee("Fancy",18000,55),
new Employee("Lion",4000,26)
);
System.out.println(st_ob.CountEmp(emp_list));
//问题3 测试:qa
st_ob.transactionTest();
}
}
4. Fork&Join框架
======== 返回目录 ========
《《《 上一篇 Java 8 Lamda表达式
》》》 下一篇 Git 和 intellij idea使用
网友评论