流中间操作在应用到流上,返回一个新的流。
-
map
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
一个元素类型为 T 的流转换成元素类型为 R 的流,这个方法传入一个Function的函数式接口,接收一个泛型T,返回泛型R,map函数的定义,返回的流,表示的泛型是R对象
//使用的People对象 public class People { private String name; private int age; ...省略get,set方法 } //将String转化为People对象 Stream.of("小王:18","小杨:20").map(new Function<String, People>() { @Override public People apply(String s) { String[] str = s.split(":"); People people = new People(str[0],Integer.valueOf(str[1])); return people; } }).forEach(people-> System.out.println("people = " + people)); } //获取姓名 List<People> peoples.... peoples.stream.map(people -> people.getName()).collect(toList()); peoples.stream.map(People::getName).collect(toList()); //将每一个Employee的年龄增加一岁 //将性别中的“M”换成“male”,F换成Female public static void main(String[] args){ Employee e1 = new Employee(1,23,"M","Rick","Beethovan"); Employee e2 = new Employee(2,13,"F","Martina","Hengis"); Employee e3 = new Employee(3,43,"M","Ricky","Martin"); Employee e4 = new Employee(4,26,"M","Jon","Lowman"); Employee e5 = new Employee(5,19,"F","Cristine","Maria"); Employee e6 = new Employee(6,15,"M","David","Feezor"); Employee e7 = new Employee(7,68,"F","Melissa","Roy"); Employee e8 = new Employee(8,79,"M","Alex","Gussin"); Employee e9 = new Employee(9,15,"F","Neetu","Singh"); Employee e10 = new Employee(10,45,"M","Naveen","Jain"); List<Employee> employees = Arrays.asList(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); /*List<Employee> maped = employees.stream() .map(e -> { e.setAge(e.getAge() + 1); e.setGender(e.getGender().equals("M")?"male":"female"); return e; }).collect(Collectors.toList());*/ List<Employee> maped = employees.stream() .peek(e -> { e.setAge(e.getAge() + 1); e.setGender(e.getGender().equals("M")?"male":"female"); }).collect(Collectors.toList()); System.out.println(maped);
-
flatMap
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
这个接口,跟map一样,接收一个Fucntion的函数式接口,不同的是,Function接收的第二个参数是一个Stream流;方法,返回的也是泛型R,具体的作用是把两个流,变成一个流返回
map和flatMap的区别:我个人认为,flatMap的可以处理更深层次的数据,入参为多个list,结果可以返回为一个list,而map是一对一的,入参是多个list,结果返回必须是多个list。通俗的说,如果入参都是对象,那么flatMap可以操作对象里面的对象,而map只能操作第一层。
// flatMap 提取 List<Students> map 提取年龄 List<Integer> ages = grades.stream().flatMap(grade -> grade.getStudents().stream()).map(Student::getAge).collect(Collectors.toList()); //将“hello”,“world”两个字符串组成的集合,元素的每一个字母打印出来 List<String> words = Arrays.asList("hello", "word"); words.stream() .flatMap(w -> Arrays.stream(w.split(""))) // [h,e,l,l,o,w,o,r,l,d] .forEach(System.out::println); //分享一个flatMap的复杂操作,实现List<Data1>和List<Data2>根据Id进行连接, //将连接结果输出为一个List<OutputData> @Data @AllArgsConstructor public class Data1 { private int id; private String name; private int amount; } @Data @AllArgsConstructor public class Data2 { private int id; private String name; private String type; } @Data @AllArgsConstructor public class OutputData { private int id; private String name; private String type; private int amount; } @Test public void intersectByKeyTest(){ List<Data2> listOfData2 = new ArrayList<Data2>(); listOfData2.add(new Data2(10501, "JOE" , "Type1")); listOfData2.add(new Data2(10603, "SAL" , "Type5")); listOfData2.add(new Data2(40514, "PETER", "Type4")); listOfData2.add(new Data2(59562, "JIM" , "Type2")); listOfData2.add(new Data2(29415, "BOB" , "Type1")); listOfData2.add(new Data2(61812, "JOE" , "Type9")); listOfData2.add(new Data2(98432, "JOE" , "Type7")); listOfData2.add(new Data2(62556, "JEFF" , "Type1")); listOfData2.add(new Data2(10599, "TOM" , "Type4")); List<Data1> listOfData1 = new ArrayList<Data1>(); listOfData1.add(new Data1(10501, "JOE" ,3000000)); listOfData1.add(new Data1(10603, "SAL" ,6225000)); listOfData1.add(new Data1(40514, "PETER" ,2005000)); listOfData1.add(new Data1(59562, "JIM" ,3000000)); listOfData1.add(new Data1(29415, "BOB" ,3000000)); List<OutputData> result = listOfData1.stream() .flatMap(x -> listOfData2.stream() .filter(y -> x.getId() == y.getId()) .map(y -> new OutputData(y.getId(), x.getName(), y.getType(), x.getAmount()))) .collect(Collectors.toList()); System.out.println(result); }
-
peek
java Stream<T> peek(Consumer<? super T> action)
(1) Consumer是没有返回值的,它只是对Stream中的元素进行某些操作,但是操作之后的数据并不返回到Stream中,所以Stream中的元素还是原来的元素。
(2) peek主要被用在debug用途。Stream.of("one", "two", "three","four").filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); //输出: Filtered value: three Mapped value: THREE Filtered value: four Mapped value: FOUR //为什么只作为debug使用呢?我们再看一个例子: Stream.of("one", "two", "three","four").peek(u -> u.toUpperCase()) .forEach(System.out::println); //输出: one two three four //可以看到stream中的元素并没有被转换成大写格式。 //再看一个map的对比: Stream.of("one", "two", "three","four").map(u -> u.toUpperCase()) .forEach(System.out::println); //输出: ONE TWO THREE FOUR //可以看到map是真正的对元素进行了转换。 //当然peek也有例外,假如我们Stream里面是一个对象会怎么样? @Data @AllArgsConstructor static class User{ private String name; } List<User> userList=Stream.of(new User("a"),new User("b"),new User("c")) .peek(u->u.setName("kkk")).collect(Collectors.toList()); log.info("{}",userList); //输出结果: 10:25:59.784 [main] INFO com.flydean.PeekUsage - [PeekUsage.User(name=kkk), PeekUsage.User(name=kkk), PeekUsage.User(name=kkk)] //我们看到如果是对象的话,实际的结果会被改变。
(3)结论
我们看下peek和map的定义:Stream<T> peek(Consumer<? super T> action) <R> Stream<R> map(Function<? super T, ? extends R> mapper);
a. peek接收一个Consumer,而map接收一个Function。
b. Consumer是没有返回值的,它只是对Stream中的元素进行某些操作,但是操作之后的数据并不返回到Stream中,所以Stream中的元素还是原来的元素。
c. 而Function是有返回值的,这意味着对于Stream的元素的所有操作都会作为新的结果返回到Stream中。
d. 这就是为什么peek String不会发生变化而peek Object会发送变化的原因。