1.Lambda表达式
1.1 Lambda表达式简介
Lambda表达式是 jdk1.8 引入的一个新特性,它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性之一。
特点:
Lambda表达式的引入简化了匿名内部类的语法,让代码更加简洁明了。
Lambda表达式提供了一种便捷的语法形式,使得函数可以作为参数传递给方法,或者作为返回值返回。
Lambda表达式的引入使得Java在并行编程方面具备了更好的支持。
lambda表达式本质来讲,是一个匿名函数(匿名方法)。
1.2 Lambda基础语法
2.1 语法与解析
语法:
(parameters) -> expression 或 (parameters) -> { statements;}
解析:
箭头(->)将参数与Lambda主体分隔开来。
参数部分:
参数可以是任意合法的Java参数列表,可以为空或包含一个或多个参数。
参数列表的类型名可以省略。 不能出现有些省略了,有些没有省略的情况。
如果参数列表中,参数的数量有且只有一个,则小括号可以省略。
Lambda主体:
Lambda主体可以是一个表达式,表达式外的大括号,可加可不加。 没有大括号时,return关键字必须省略。
也可以是一个代码块。将按照常规的Java语法执行,可能需要使用return语句来返回值。
2.2 语法案例
语法:
1. 无参数的Lambda表达式:
() -> System.out.println("Hello, Lambda!");
2. 带有参数的Lambda表达式:
(int m) -> System.out.println(m);
或 (m) -> System.out.println(m);
或 m -> System.out.println(m);
(int x, int y) -> System.out.println(x + y);
或者 (x, y) -> System.out.println(x + y);
3. 带有多行代码的Lambda表达式:
(x, y) -> { int sum = x + y;
System.out.println("Sum: " + sum);
return sum; }
1.3 Lambda的应用
3.1 初窥门径
应用场景:lambda表达式,只能作用于函数式接口。
函数式接口:有且只有一个抽象方法的接口
引入案例代码(匿名内部类用Lambda表达式的写法)
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class _01InnerClassDemo {
public static void main(String[] args) {
List<Person> ps = new ArrayList<>();
ps.add(new Person("张三", 20));
ps.add(new Person("李四", 30));
ps.add(new Person("王五", 40));
ps.add(new Person("赵六", 50));
// Comparator c = new Comparator<Person>() {
// @Override
// public int compare(Person o1, Person o2) {
// return o1.getAge()-o2.getAge();
// }
// };
// Comparator<Person> c = (o1,o2) -> o2.getAge()-o1.getAge();
// Collections.sort(ps,c);
Collections.sort(ps,(o1, o2) -> o2.getAge()-o1.getAge());
System.out.println(ps);
}
}
class Person implements Comparable<Person>{
private String name;
private int age;
public Person(){
}
public Person(String name , int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person o) {
return age-this.age;
}
}
3.2 登堂入室
Lambda表达式的应用:
1.Lambda表达式实际上就是匿名内部类的简化版本
2.Lambda表达式是JDK1.8引入的一个最重要的新特性,另一个就是集合的流式编程。 3.Lambda表达式是java为了扩展函数式编程引入的。
4.Lambda表达式可以理解为是一个匿名函数(匿名方法:方法没有名字)
5.Lambda表达式只能作用于函数式接口,有且只有一个抽象方法的接口(可以有静态方法,默认方法,静态常量等)。
案例演示
public class _02LambdaDemo01 {
public static void main(String[] args) {
//2.测试类实现
Test1 test1 = new Test1();
test1.print();
//3.使用匿名内部类的方式,实现NoParameterNoReturn接口,打印"我一定能学会java"
NoParameterNoReturn npnr = new NoParameterNoReturn() {
@Override
public void print() {
System.out.println("我一定能学会java");
}
};
npnr.print();
//4.使用lambda表达式,实现NoParameterNoReturn接口,打印"哈哈哈,我哭了...";
NoParameterNoReturn npnr2 = ()-> System.out.println("哈哈哈,我哭了...");
npnr2.print();
//5.使用lambda表达式,实现OneParameterNoReturn接口,打印"'我喜欢'+形参",并测试打印,传入'苹果'
OneParameterNoReturn oneturn = a -> System.out.println("我喜欢"+a);
oneturn.print("苹果");
//6.使用lambda表达式,实现MuilParameterNoReturn接口,打印两个参数拼接的效果,测试传入"我今年","18"
MuilParameterNoReturn mpnr = (a,b)-> System.out.println(a+b);
mpnr.print("我今年",18);
//7.使用lambda表达式,实现NoParameterReturn接口,计算两个随机数,区间[25,40]的和",测试。
NoParameterReturn npr = ()-> {
int a=(int) (Math.random()*16+25);
int b=(int) (Math.random()*16+25);
return a+b;
};
System.out.println("两个随机数的和"+npr.calculate());
//8.使用lambda表达式,实现OneParameterReturn接口,计算形参的立方,测试传入3
OneParameterReturn opr = a -> a*a*a ;
System.out.println("3的立方: "+opr.calculate(3));
//9.使用lambda表达式,实现MuilParameterReturn接口,计算两个形参的立方和,测试传入3和4
MuilParameterReturn mpr = (a,b) -> a*a*a+b*b*b;
System.out.println("3的立方和4的立方的和:"+mpr.calculate(3,4));
}
}
//1.使用实现类的方式,实现NoParameterNoReturn接口,打印"java编程真简单"
class Test1 implements NoParameterNoReturn {
@Override
public void print() {
System.out.println("java编程真简单");
}
}
// 里面的抽象方法,没有形参,也没有返回值。
interface NoParameterNoReturn{
void print();
}
//一个形参,没有返回值
interface OneParameterNoReturn{
void print(String info);
}
//多个形参,没有返回值
interface MuilParameterNoReturn{
void print(String info,int age);
}
//没有形参,有返回值
interface NoParameterReturn{
int calculate();
}
//一个参数,带返回值
interface OneParameterReturn{
int calculate(int a);
}
//多个形参,带返回值。
@FunctionalInterface //注解是用来校验是否为函数式接口(就是接口里面是否只有一个抽象方法)
interface MuilParameterReturn{
double PI =3.14;
int calculate(int a,int b);
}
结果:
3.3 Lambda表达式在集合中的应用
Lambda表达式在Collection接口中的使用主要涉及对集合进行迭代、筛选和转换等操作。在Java 8及以上的版本中,Collection接口增加了一些默认方法,例如forEach()
、removeIf()
和stream()
等,使得使用Lambda表达式更加方便。
使用条件:
第一个:排序时,使用比较器的时候
第二个:迭代时
第三个:根据条件删除元素
案例代码:
import java.util.*;
public class _03LambdaDemo02_InList {
public static void main(String[] args) {
//测试第一种:集合的排序
List<String> list = new ArrayList<String>();
list.add("michael");
list.add("david");
list.add("peter");
list.add("bob");
list.add("lucy");
System.out.println(list);
//按照字符串长度降序:比较器使用了lambda表达式的方法
Collections.sort(list,(a,b)->b.length()-a.length());
System.out.println(list);
//测试第二种:集合的迭代
Integer[] arr = new Integer[]{1,2,3,4,5};
List<Integer> nums = Arrays.asList(arr);
//forEach方法
/*
forEach(Consumer c)的源码:
for(T t:this){
c.accept(t);
}
Consumer是一个函数式接口:里面的抽象方法
void accept(T t)
因此只需要向forEach()方法中传入 accept的匿名函数,也就是lambda表示即可
*/
nums.forEach(num->System.out.println(num));
System.out.println("-------------------------------");
//继续简化
nums.forEach(System.out::println);
System.out.println("-----------set的迭代--------------");
//set接口的迭代
Set<Integer> set = new HashSet<>(nums);
// System.out.println(set);
set.forEach(System.out::println);
System.out.println("-----------map的迭代--------------");
Map<String, Integer> map = new HashMap<>();
map.put("michael", 20);
map.put("david", 30);
map.put("peter", 40);
map.put("bob", 50);
map.put("lucy", 60);
System.out.println(map);
//key的迭代
map.keySet().forEach(key->System.out.println(key+":"+map.get(key)));
map.keySet().forEach(System.out::println);
//entrySet的迭代
map.entrySet().forEach(e-> System.out.println(e.getKey()+"-->"+e.getValue()));
map.entrySet().forEach(System.out::println);
//values的迭代
map.values().forEach(System.out::println);
/*
根据条件删除元素
*/
List <Integer> list2 = Arrays.asList(18,17,39,5,17);
List <Integer> list3 = new ArrayList<>(list2);
/*
removeIf(Predicate filter):
源码解析
内部逻辑就是一个迭代器遍历集合,根据条件做删除操作
条件就是filter的test方法。
Predeicate 是一个函数式接口,里面有boolean test(T t)方法,因此我们在使用时就是写一个lambda表达式,来实现test方法即可。
*/
list3.removeIf(m->m.equals(17));
}
}
1.4 变量的捕获
在Java中,匿名内部类可以捕获外部变量,即在匿名内部类中引用并访问外部作用域的变量。这种行为称为变量捕获(Variable Capturing)。
变量的捕获: 在内部对外部的变量的引用和访问
1. 实例变量(成员变量,属性,全局变量)
2. 静态变量
3. 方法形参: 访问的方法形参也只能访问,不能覆盖。
4. 本地变量(局部变量):内部类可以捕获并访问声明为final的本地变量。从Java 8开始,final关键字可以省略,但该变量实际上必须是最终的(即不可修改)。总结:
1.匿名内部类访问的局部变量(方法形参,本地变量)都是只能访问,不能覆盖。
2.lambda表达式也可以访问上述四种变量,依然是对局部变量只能访问,不能覆盖。
代码演示:
public class _01InnerClassDemo {
private int a; //实例变量
private static int b; //静态变量
static {
b=2;
}
public _01InnerClassDemo() {
a = 1;
}
public void M1(int c){
int d = 4;
MyTest mt = new MyTest() {
@Override
public void test1() {
//访问外部类的成员变量:外部类名.this.成员变量 或者直接写。
System.out.println("成员变量(instance variable):"+a);
//访问外部类的静态变量: 外部类名.静态变量, 或者直接写。
System.out.println("static variable: "+b);
//匿名内部类访问的方法形参也只能访问,不能覆盖。
System.out.println("method parameter: "+c);
// 匿名内部类访问的局部变量,是默认被final修饰的。final修饰的变量只能初始化一次。
System.out.println("native variable: "+d);
}
};
mt.test1();
}
public void m2(int c){
int d = 4;
MyTest mt = () -> {
//访问外部类的成员变量:外部类名.this.成员变量 或者直接写。
System.out.println("成员变量(instance variable):"+a);
//访问外部类的静态变量: 外部类名.静态变量, 或者直接写。
System.out.println("static variable: "+b);
//访问的方法形参也只能访问,不能覆盖。
System.out.println("method parameter: "+c);
//访问的局部变量,是默认被final修饰的。final修饰的变量只能初始化一次。
System.out.println("native variable: "+d);
};
mt.test1();
}
public static void main(String[] args) {
_01InnerClassDemo demo = new _01InnerClassDemo();
// demo.M1(1);
demo.m2(3);
}
}
interface MyTest{
void test1();
}
2. 集合的流式编程
2.1 流式编程的简介
1)Stream编程的简介
Stream是JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一。(另外一个是 lambda表达式)。
Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储的。流更像是 一个迭代器,可以单向的遍历一个集合中的每一个元素,并且不可循环。
2)为什么要使用集合的流式编程
有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果。在这个过程中,集合的流式编程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行操作(删除、过滤、映射...)。每次的操作结果也是一个流对象,可以对这个流再进行其他的操作。
3)使用流式编程的步骤
通常情况下,对集合中的数据使用流式编程,需要经过以下三步。
获取数据源,将数据源中的数据读取到流中。
对流中的数据进行各种各样的处理。
对流中的数据进行整合处理。
在上述三个过程中,
过程2中,有若干方法,可以对流中的数据进行各种各样的操作,并且返回流对象本身,这样的操作,被称为 -- 中间操作。
过程3中,有若干方法,可以对流中的数据进行各种处理,并关闭流,这样的操作,被称为 -- 最终操作。
在中间操作和最终操作中,基本上所有的方法参数都是函数式接口,可以使用lambda表达式来实现。 使用集合的流式编程,简化代码量,需要大量使用 lambda 表达式。
2.2 数据源的获取
1)数据源的介绍
数据源,顾名思义,既是流中的数据的来源。是集合的流式编程的第一步,将数据源中的数据读取到流中,进行处理。注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序... ,此时是不会影响数据源中的数据的 。
2) 数据源的获取
这个过程,其实是将一个容器中的数据,读取到一个流中。因此无论什么容器作为数据源,读取到流中 的方法返回值一定是一个Stream。
数据源的获取
集合的流式编程:
1.传统方式,如果对集合中的元素做处理时,可能要书写大量的代码,比如增加,删除,过滤等
2.集合的流式编程:是JDK1.8引入的两个重要特性之一。
3.集合的流逝编程是对传统方式的一种简化操作。
4.集合的流式变成,分三步:
--第一步: 获取数据源(关联数据源),返回Stream对象
--第二步: 对Stream对象进行各种处理,处理后的结果依然是Stream对象
--第三步: 对Stream对象的最后整合处理。处理后的结果一般情况下不再是Stream对象,可能是一个具体的数字,字符串,或者是一个新的集合。
--注意: 整个过程中,数据源本身并不会发生变化。
代码演示(获取数据源):
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class _01DataSourceGet {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
/*
如果想要对这个集合进行流式编程,第一步,必须获取数源(关联数据源)
*/
//1.获取的流对象,是串行的,不是并行的,好比只有一个人去工作。
Stream<Integer> s1 = list.stream();
//2. 获取的流对象,是并行的,好比有多个人同时工作。效率高。
Stream<Integer> integerStream = list.parallelStream();
}
}
2.3 最终操作
1) 最终操作的简介
将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历、数据统计... ,通过 最终操作,需要掌握如何从流中提取出来我们想要的信息。
注意事项:最终操作,之所以叫最终操作,是因为,在最终操作执行结束后,会关闭这个流,流中的所有数据都会销毁。如果使用一个已经关闭了的流,会出现异常。
2)Collect
集合的流式编程的最终操作:
1.将流中的数据整合到一起。可以存入一个新的集合,也可以遍历,或者统计。
2. 最终操作,会关闭这个流,流里的数据都会被销毁。如果在关闭流的基础上,继续操作流,会报如下错误
stream has already been operated upon or closed最终操作常用的方法如下:
1.collect: 搜集方法,可以将流的数据搜集成一个新的集合。
该方法的形参是一个Collector接口(非函数式接口),可以用来指定搜集规则。
通常情况下,不需要程序员自己实现,Collectors工具类里提供的方法够用。
Collect方法代码演示:
public class _02Final_collect {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
//获取数据源
Stream<Integer> stream = nums.stream();
//搜集1: 搜集成List集合
// List<Integer> c1 =stream.collect(Collectors.toList());
//搜集2: 搜集成Set集合
// Set<Integer> c2 = stream.collect(Collectors.toSet());
// System.out.println(c2);
//搜集3 搜集成Map集合
/*
Collectors.toMap(keyMapper,valueMapper)
keyMapper是一个函数式接口,里面有一个R apply(T t)抽象方法,我们就是通过lambda表达式来重写apply方法
valueMapper亦如此。
*/
Map<String, Integer> c3 = stream.collect(Collectors.toMap((e) -> "key" + e, e -> e));
System.out.println(c3);
}
}
3)reduce
2. reduce方法:将流中的数据按照一定的规则聚合起来。
代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class _03Final_reduce {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
//计算数据源的元素之和 方法参数也是lambda表达式: 对应的抽象方法 R apply(T t ,U u);
// 返回的类型:Optional,需要调用它的get方法,获取里面的数据。
// Optional<Integer> reduce = stream.reduce((a, b) -> a + b); //15
/*
从下面的案例可以得出结论: a变量接收的是数据源中的第一个元素,然后b变量接收的是剩下的元素。
a -= b;
a =- b;
*/
Optional<Integer> reduce = stream.reduce((a, b) -> a - b);// -13
int result = reduce.get();
System.out.println("计算结果:"+result);
}
}
4)count
count方法:统计流中的元素数量。
count测试代码
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class _04Final_count {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
/*
count(): 用于统计数据源的元素个数。
底层源码: return mapToLong(e -> 1L).sum();
即将元素映射成1L,然后求和。
*/
long count = stream.count();
System.out.println(count);
}
}
5)forEach Max Min
forEach方法:迭代、遍历流中的数据。
Max 方法:获取流中的最大的元素。
Min 方法:获取流中的最小的元素。
测试代码:
package com.se.day08.cStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class _05Final_forEach_max_min {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
/*
forEach方法:对流中的数据进行遍历,注意遍历完毕,流就关闭了。
*/
stream.forEach(num -> System.out.println(num));
// stream.forEach(System.out::print);
/*
max(Comparator c):
获取排序后的最后一个元素
*/
Integer integer = nums.stream().max((a, b) -> a-b).get();
System.out.println(integer);
/*
min(Comparator c):
获取排序后的第一个元素
*/
Integer integer2 = nums.stream().min((a, b) -> a - b).get();
System.out.println(integer2);
}
}
6)Matching
allMatch: 只有当流中所有的元素,都匹配指定的规则,才会返回 true
anyMatch: 只要流中有任意的数据,满足指定的规则,都会返回 true
noneMatch: 只有当流中的所有的元素,都不满足指定的规则,才会返回true
package com.se.day08.cStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
/*
AllMatch: 当数据源中的所有元素都满足匹配条件,才返回true。
AnyMatch: 当数据源中的任意一元素满足匹配条件,就返回true。
NoneMatch: 当数据源中的所有元素都不满足匹配条件,返回true。
*/
public class _06Final_Matching {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
boolean b = stream.allMatch(a -> a < 10);
System.out.println("allMatch测试: "+b);
Stream<Integer> stream1 = nums.stream();
boolean b1 = stream1.anyMatch(a-> a <2);
System.out.println("anyMatch测试: "+b1);
Stream<Integer> stream2 = nums.stream();
boolean b2 = stream2.noneMatch(a-> a <0);
System.out.println("noneMatch测试: "+b2);
}
}
7)find
findFirst: 从流中获取一个元素(一般情况下,是获取的开头的元素)
findAny: 从流中获取一个元素(一般情况下,是获取的开头的元素)
这两个方法,绝大部分情况下,是完全相同的,但是在多线程的环境下, findAny和find返回的结果可能不一样。
测试代码
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
public class _07Final_find {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
Stream<Integer> stream = nums.stream();
//串的流演示
Optional<Integer> first = nums.stream().findFirst();
int e1 = first.get();
System.out.println(e1);
int e2 = nums.stream().findAny().get();
System.out.println(e2);
//并行的流
Integer e3 = nums.stream().findFirst().get();
Integer e4 = nums.stream().findAny().get();
System.out.println("e3 " + e3+",e4 "+e4);
}
}
2.4 中间操作
1)中间操作的简介
中间操作是流式处理中的步骤,它们会返回流本身,允许链式调用多个操作。这些操作通常是惰性的,意味着它们不会立即执行,而是等待终端操作触发时才开始处理数据。
中间操作是流式编程中构建复杂数据处理管道的关键。通过链式调用多个中间操作,可以灵活地处理集合中的数据,而无需编写复杂的迭代逻辑。然而,请注意,中间操作本身不会执行任何数据处理;它们只是定义了数据处理的步骤,等待终端操作触发时才开始执行。
2)filter 与distinct
filter:通过给定的谓词(一个返回布尔值的函数)过滤流中的元素。
distinct :去重
演示代码:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class _01Filter_distinct {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(1);
nums.add(2);
nums.add(3);
nums.add(4);
nums.add(5);
nums.add(2);
nums.add(4);
/*
filter(...) 过滤出来满足条件的数据
比如:想要所有的奇数
*/
List<Integer> c1 = nums.stream().filter(n -> n % 2 != 0).collect(Collectors.toList());
System.out.println(c1);
/*
distinct() 去重 lambda表达式,可以理解为一个没有名字的方法
*/
nums.stream().distinct().forEach(e -> System.out.print(e + " "));
}
}
class Class1{
public static<T> void m1(T a){
System.out.println(a);
}
}
3)sorted、limit与skip
sorted():根据元素的自然顺序对流进行排序。
sorted(Comparator c) : 根据自己定义的比较器排序,自定义比较规则
limit(int size): 截取流中前size个元素
skip(int size): 忽略流中前size个元素
测试代码如下:
import java.util.ArrayList;
import java.util.List;
public class _02sorted_limit_skip {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
//sorted():默认升序排序
// sorted(Comparator c) 自定义比较规则
nums.stream().sorted((n,m)->m-n).forEach(System.out::println);
//limit(Long size):表示截取流中的前size个元素
nums.stream().limit(2).sorted((a,b)->a-b).forEach(s->System.out.print(s + " "));
System.out.println("-------------------------");
/*
skip(long size):
*/
nums.stream().filter(e->e!=2).sorted().skip(2).forEach(System.out::println);
}
}
4)map与mapToInt(mapToLong、mapToDouble)
map(....): 将元素映射成另外一种类型 将上述元素映射成字符串类型
mapToInt(......): 将元素映射成intStream
mapToLong(......): 将元素映射成longStream
mapToDouble(......): 将元素映射成doubleStream
测试代码如下:
package com.se.day08.dStreammMid;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class _03Map_mapToInt {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<Integer>();
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
nums.add(1);
/*
map(....): 将元素映射成另外一种类型
将上述元素映射成字符串类型
*/
List<String> collect = nums.stream().map(e -> "" + e * 10).collect(Collectors.toList());
System.out.println(collect);
// System.out.println(nums.stream().);
/*
mapToInt(......): 将元素映射成intStream
mapToLong(......): 将元素映射成longStream
mapToDouble(......): 将元素映射成doubleStream
*/
int sum = nums.stream().mapToInt(e -> 1).sum();
System.out.println("元素个数:"+sum);
}
}
4)flatMap
flatMap: 扁平式映射。 一般针对的都是集合元素仍然是一个集合。
普通的集合[1,2,3,4,5] 集合元素式集合的:[[1,2,10],[1,3,4],[2,4,5]]
扁平式映射: 就是将元素式集合的这种特殊集合,转成普通的集合。
如将集合 [[1,2,10],[1,3,4],[2,4,5]] 转成: [1,2,10,1,3,4,2,4,5]。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class _04flatMap {
public static void main(String[] args) {
//集合out的元素依然是集合。
List<List<Integer>> out = new ArrayList<>();
out.add(Arrays.asList(1,2,3));
out.add(Arrays.asList(4,5,6));
out.add(Arrays.asList(7,8,9));
//flatMap(....)传入一个lambda表达式: e ->e.stream() 压平了。
long count = out.stream().flatMap(e -> e.stream()).count();
System.out.println(count);
}
}
2.5 综合案例
需求 : 一个集合中存储了了若干个Student对象 , 要求查询出以下结果 :
1. 所有及格的学生信息
2. 所有及格的学生姓名
3. 所有学生的平均成绩
4. 班级的前3名(按照成绩)
5. 班级的3-10名(按照成绩)
6. 所有不不及格的学生平均成绩
7. 将及格的学生 , 按照成绩降序输出所有信息
8. 班级学生的总分
代码演示:
Student类
public class Student implements Comparable<Student>{
private String name;
private double score;
public Student(){}
public Student(String name, double score) {
this.name = name;
this.score = score;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Student o) {
return 0;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}'+'\n';
}
}
功能实现:
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalDouble;
import java.util.stream.Stream;
public class H1 {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("张三",99));
students.add(new Student("李四",89));
students.add(new Student("王五",59));
students.add(new Student("赵六",65));
students.add(new Student("宋茜",79));
students.add(new Student("齐大",100));
students.add(new Student("乔二",93));
students.add(new Student("陈三",66));
students.add(new Student("忘忧",69));
students.add(new Student("星辰",94));
students.add(new Student("大海",13));
students.add(new Student("八六",86));
students.add(new Student("热气",50));
System.out.println(students);
Stream<Student> studentStream = students.stream().filter(e -> e.getScore() >= 60);
//所有及格的学生信息
System.out.println("-------------------------------------------------------");
System.out.println("1.所有及格的学生信息:");
studentStream.forEach(System.out::print);
System.out.println("-------------------------------------------------------");
System.out.println("2.所有及格学生的姓名: ");
Stream<Student> studentStream1 = students.stream().filter(e -> e.getScore() >= 60);
studentStream1.forEach(e -> System.out.println(e.getName()));
System.out.println("-------------------------------------------------------");
OptionalDouble average = students.stream().mapToDouble(Student::getScore).average();
System.out.println("3.所有学生的平均成绩为:"+average.getAsDouble());
System.out.println("-------------------------------------------------------");
System.out.println("4.前三名:");
students.stream().sorted((a,b)-> (int) (b.getScore()-a.getScore())).limit(3).forEach(System.out::print);
System.out.println("--------------------------------------------------------");
System.out.println("5.第3到10名");
students.stream().sorted((a,b)->(int)(b.getScore()-a.getScore())).skip(2).limit(7).forEach(System.out::print);
System.out.println("--------------------------------------------------------");
OptionalDouble average1 = students.stream().filter(a -> a.getScore() < 60).mapToDouble(e -> e.getScore()).average();
System.out.println("6.不及格的平均成绩为:"+average1.getAsDouble());
System.out.println("--------------------------------------------------------");
System.out.println("7.所有及格的学生按成绩降序输出所有信息");
students.stream().filter(e -> e.getScore() >= 60).sorted((a,b)->(int) (b.getScore()-a.getScore())).forEach(System.out::print);
System.out.println("--------------------------------------------------------");
System.out.println("8.班级总分:");
double sum = students.stream().mapToDouble(Student::getScore).sum();
System.out.println(sum+"分");
}
}
结果展示: