目录
(4)语法格式四:有两个以上参数,有返回值,并且 Lambda 体中有多条语句
(5)语法格式五:若 Lambda 体中只有一条语句,return 和 大括号 都可以省略不写
(6)语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
●方式1:通过Collection 系列集合提供的stream()返回一个顺序流 或parallelStream() 返回一个并行流
●方式2:Arrays 的静态方法 stream() 获取数组流
●方式3:静态方法 Stream.of() 通过显示值创建一个流。它可以接收任意数量的参数
●方式4:静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
一、Lambda表达式
1、为什么使用Lambda表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
2、Lambda表达式的基础语法(都要基于一个接口)
Lambda 表达式在Java 语言中引入了一个新的语法元 素和操作符。这个操作符为 “->” , 该操作符被称 为 Lambda 操作符或剪头操作符。它将 Lambda 分为 两个部分:
- 左侧:指定了 Lambda 表达式需要的所有参数
- 右侧:指定了 Lambda 体,即 Lambda 表达式要执行 的功能。
(1)语法格式一:无参,无返回值
Runnable r = ()-> System.out.println("Hello Lambda!");
@Test
public void test8(){
/*
局部内部类中应用了同级别的局部变量,jdk1.7以前该局部变量必须用final修饰,
以后默认被final修饰,不需再手动添加final(其值还是不能被改变)
*/
int num = 0;
//匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hello hello"+num);
}
};
runnable.run();
System.out.println("==============================");
//Lambda表达式
Runnable r = () -> System.out.println("hello hello" +num);
r.run();
}
(2)语法格式二:一个参数,并且无返回值
Consumer<String> con = (x) -> System.out.println(x);
@Test
public void test9(){
Consumer<String> con = (x) -> System.out.println(x); //Consumer--jdk1.8中的一个接口
con.accept("xxxxxxxxxxxxxxxxeeee");//accept--Consumer接口中的一个方法
}
(3)语法格式三:若只有一个参数,参数的小括号可以不写
Consumer<String> con = x -> System.out.println(x);
@Test
public void test9(){
Consumer<String> con = x -> System.out.println(x); //Consumer--jdk1.8中的一个接口
con.accept("xxxxxxxxxxxxxxxxeeee");
}
(4)语法格式四:有两个以上参数,有返回值,并且 Lambda 体中有多条语句
Comparator<Integer> com = (x, y) -> { System.out.println("lalalal"); System.out.println("aaaaa"); return Integer.compare(x,y); };
(5)语法格式五:若 Lambda 体中只有一条语句,return 和 大括号 都可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
(6)语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
3、Lambda 表达式需要“函数式接口”的支持
(1)函数式接口:接口中只有一个抽象方法的接口,可以使用 @FunctionalInterface 修饰
4、Lambda 小练习
/*
1、 调用 Collections.sort(),通过定制排序比较俩个User(先按年龄比,年龄相同,按姓名比)
*/
@Test
public void test13(){
Collections.sort(users, (u1, u2) -> {
if(u1.getAge()==u2.getAge()){
return u1.getName().compareTo(u2.getName());
}else{
// return Integer.compare(u1.getAge(), u2.getAge()); //升序
return -Integer.compare(u1.getAge(), u2.getAge());//降序
}
});
for (User user : users) {
System.out.println(user);
}
}
/*
2、①声明函数式接口,接口中声明抽象方法public String getValue(String s);
②声明类TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值
③再将一个字符串的第2个和第4个索引位置进行截取子串
*/
@FunctionalInterface
public interface MyString {
public String getValue(String s);
}
public String ZhuanHuan(String s, MyString ms){
return ms.getValue(s);
}
@Test
public void test14(){
String str = "asldinewinnn";
String result = ZhuanHuan(str, (s) -> s.toUpperCase());
System.out.println(result);
String s1 = ZhuanHuan(str, (s) -> s.substring(2, 5));
System.out.println(s1);
}
/*
3、①声明一个带两个泛型的函数式接口,泛型类型<T,R> T为参数,R为返回值
②接口中声明对应抽象方法
③在TestLambda类中声明方法,使用接口作为参数,计算两个long类型参数的和
④在计算两个long类型参数的乘积
*/
@FunctionalInterface
public interface MyLong<T , R> {
public R getValue(T t1, T t2);
}
public Long getValue(Long l1, Long l2, MyLong<Long, Long> myLong){
return myLong.getValue(l1,l2);
}
@Test
public void test15(){
Long sum = getValue(100L, 200L, (x, y) -> x + y);
System.out.println(sum);
Long chengji = getValue(200L, 300L, (x, y) -> x * y);
System.out.println(chengji);
}
二、函数式接口
1、函数式接口:
接口中只有一个抽象方法的接口,可以使用 @FunctionalInterface 修饰
2、Java8 内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型接口 | T | void | 对类型为T的对象应用操作, 包含方法:void accep(T t); |
Supplier<T> 供给型接口 | 无 | T | 返回类型为T的对象, 包含方法: T get(); |
Function<T, R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果,结果 是R类型的对象, 包含方法:R apply(T t); |
Predicate<T> 断定型接口 | T | boolean | 确定类型为T的对象是否 满足某约束,并返回 boolean 值。 包含方法 boolean test(T t); |
小例子:
public class TestFunction {
// Consumer<T> 消费型接口
public void play(double money, Consumer<Double> consumer){
consumer.accept(money);
}
@Test
public void test1(){
play(10000, (money) -> System.out.println("每次消费" + money + "元"));
}
// Supplier<T> 供给型接口
//需求:产生指定个数的整数,并放入集合中
public List<Integer> addList(int num, Supplier<Integer> supplier){
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < num ; i++) {
Integer integer = supplier.get();
list.add(integer);
}
return list;
}
@Test
public void test2(){
List<Integer> result = addList(10, () -> (int) (Math.random() * 100));
for (Integer integer : result) {
System.out.println(integer);
}
}
//Function<T, R>:函数型接口
//需求:对字符串进行处理
public String strHandler(String str, Function<String, String > function){
String apply = function.apply(str);
return apply;
}
@Test
public void test3(){
String result = strHandler("alalalalallaallalala", (str) -> str.toUpperCase());
System.out.println(result);
}
//Predicate<T>:断定型接口
//需求:将满足条件的字符串添加到集合中
public List<String> RequestString(List<String> lists, Predicate<String> predicate){
ArrayList<String> strings = new ArrayList<>();
for (String list : lists) {
if(predicate.test(list)){
strings.add(list);
}
}
return strings;
}
@Test
public void test4(){
List<String> strs = Arrays.asList(
"abce",
"qwer",
"rtyu",
"hjkg",
"lkjhy"
);
List<String> result = RequestString(strs, (ss) -> ss.contains("e"));
for (String s : result) {
System.out.println(s);
}
}
}
3、其他接口:
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结果。 包含方法为 R apply(T t, U u) |
UnaryOerator<T> (Function子接口) | T | T | 对类型为T的对象进行一 元运算,并返回T类型的结果。 包含方法为 T apply(T t) |
BinaryOperator<T> (BiFunction子接口) | T, T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。 包含方法为 T apply(T t1, T t2) |
BiConsumer<T, U> | T, U | void | 对类型为T, U 参数应用 操作。 包含方法为 void accept(T t, U u) |
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> | T | int long double | 分别计算int、long、double值的函数 |
IntFunction<R> LongFunction<R> DoubleFunction<R> | int long double | R | 参数分别为int、long、double类型的函数 |
三、方法引用与构造器引用
1、方法引用
当要传递给 Lambda 体的操作,已经有实现的方法了,可以使用方法引用(可以理解为 方法引用是 Lambda 表达式的另外一种表现形式)
方法引用操作符“ :: ”,将方法名和对象或类的名字分隔开来
主要有三种语法格式:
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
注意:
① Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型保持一致
②若 Lambda 参数列表中的第一个参数是 实例方法的调用者,而第二个参数是实例方法的参数(或无参数)时,可以使用ClassName :: Method
(1)对象::实例方法
@Test
public void test2(){
User user = new User();
Supplier<String> str = () -> user.getName();
String s = str.get();
System.out.println(s);
//方法引用
Supplier<Integer> ss = user :: getAge;
Integer integer = ss.get();
System.out.println(integer);
}
(2)类::静态方法
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
//等同于
Comparator<Integer> com1 = Integer::compare;
(3)类::实例方法
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
//等同于
BiPredicate<String, String> bp1 = String::equals;
2、构造器引用
(1)格式:ClassName :: new
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
//构造器引用
@Test
public void test5(){
Supplier<User> user = () -> new User();
//匹配无参构造器
Supplier<User> user1 = User::new;
User user2 = user1.get();
System.out.println(user2);
//匹配只有String name的构造器
Function<String, User> user3 = (s) -> new User(s);
Function<String, User> user4 = User::new;
User zhangsan = user4.apply("zhangsan");
System.out.println(zhangsan);
}
3、数组引用
(1)格式:type[ ] :: new
//数组引用
@Test
public void test6(){
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strings = fun.apply(10);
System.out.println(strings.length);
Function<Integer, String[]> function = String[]::new;
String[] apply = function.apply(20);
System.out.println(apply.length);
}
四、Stream API
1、什么是Stream?
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算”
注意:
①stream 自己不会存储元素
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
③Stream 操作是延迟执行的,这意味着他们会等到需要结果的时候才执行
2、Stream 的三个操作步骤:
- 创建 Stream
- 中间操作
- 终止操作
(1)创建 Stream
●方式1:通过Collection 系列集合提供的stream()返回一个顺序流 或parallelStream() 返回一个并行流
- default Stream<E> stream() : 返回一个顺序流
- default Stream<E> parallelStream() : 返回一个并行流
ArrayList<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
●方式2:Arrays 的静态方法 stream() 获取数组流
- static <T> Stream<T> stream(T[] array): 返回一个流
User[] users = new User[10];
Stream<User> stream2 = Arrays.stream(users);
●方式3:静态方法 Stream.of() 通过显示值创建一个流。它可以接收任意数量的参数
public static<T> Stream<T> of(T... values) : 返回一个流
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
●方式4:静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。
- 迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) //第二个参数是个一元运算接口
- 生成
public static<T> Stream<T> generate(Supplier<T> s)
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(10)
.forEach(System.out::println);
(2)中间操作 --不执行任何处理
多个中间操作可以连接起来形成一个流水线,除非流水 线上触发终止操作,否则中间操作不会执行任何的处理! 而在终止操作时一次性全部处理,称为“惰性求值”
-
●筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收 Lambda,从流中排除某些元素 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素【需重写对象的hashCode() 和 equals()】 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个, 则返回一个空流。与 limit(n) 互补 |
public class TestStreamAPI2 {
List<User> users = Arrays.asList(
new User("zhangsan",18,999.99),
new User("lisi",38,999.99),
new User("wangwu",50,999.99),
new User("zhaoliu",16,999.99),
new User("tianqi",8,999.99),
new User("tianqi",8,999.99)
);
//筛选与切片
/*
filter(Predicate p) 接收 Lambda , 从流中排除某些元素。
distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去 除重复元素
limit(long maxSize) 截断流,使其元素不超过给定数量。
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素 不足 n 个,则返回一个空流。与 limit(n) 互补
*/
//skip\distinct
@Test
public void test4(){
users.stream()
.filter( (user) -> user.getSalary()>500)
.skip(2)
.distinct()
.forEach(System.out::println);
}
//limit
@Test
public void test3(){
users.stream()
.filter( (user) -> {
System.out.println("短路!");
return user.getSalary()>500;
})
.limit(2)
.forEach(System.out::println); //终止操作
}
//filter
//内部迭代:迭代操作由Stream API 完成
@Test
public void test1(){
//中间操作
Stream<User> stream = users.stream()
.filter((user) -> {
System.out.println("stream api 的中间操作");
return user.getAge() > 35;
});
//终止操作
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test2(){
Iterator<User> iterator = users.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
-
●映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元 素上,产生一个新的 LongStream。 |
/*
map(Function f) 接收一个函数作为参数,该函数会被应用到每个元 素上,并将其映射成一个新的元素
flatMap(Function f) 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流
*/
//map
@Test
public void test5(){
List<String> strings = Arrays.asList("aaa", "bbb", "ccc");
strings.stream()
.map( (s) -> s.toUpperCase())
.forEach(System.out::println);
users.stream()
.map( ( User::getName))
.forEach(System.out::println);
}
//flatMap
//需求:将字符串中的字符提取出来放在集合中,然后转化成流返回
public static Stream<Character> filterCharacter(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();
}
/*
map() 和 flatMap() 类似于add(Object o) \addAll(Collection con)
add(List list) 是将这个集合添加到原集合中 [11,22, [33,44]]
addAll(List list) 是将list集合中的每个元素添加到元集合中 [11,22,33,44]
*/
@Test
public void test6(){
List<String> strings = Arrays.asList("aaa", "bbb", "ccc");
//map中间操作返回一个流,filterCharacter返回一个Stream<Character>
Stream<Stream<Character>> result = strings.stream()
.map( TestStreamAPI2::filterCharacter);
result.forEach( (sm) -> { //result中取出一个是流(sm),流还需要再去遍历
sm.forEach(System.out::println);
}
);
System.out.println("=================================");
strings.stream()
.flatMap(TestStreamAPI2::filterCharacter) //返回值 --Stream<Character>
.forEach(System.out::println);
}
-
●排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序(Comparable)排序 |
sorted(Comparator comp) | 产生一个新流,其中按定制顺序(Comparator)排序 |
@Test
public void test7(){
List<String> strings = Arrays.asList("a", "c", "w", "e");
strings.stream()
.sorted()
.forEach(System.out::println);
System.out.println("====================================");
List<User> users = Arrays.asList(
new User("zhangsan",18,999.99),
new User("lisi",38,999.99),
new User("wangwu",50,999.99),
new User("zhaoliu",16,999.99),
new User("tianqi",8,999.99),
new User("tianqiq",8,999.99)
);
users.stream()
.sorted( (u1, u2) -> {
if(u1.getAge() == u2.getAge()){
return u1.getName().compareTo(u2.getName());
}else{
return Integer.compare(u1.getAge(),u2.getAge());
}
})
.forEach(System.out::println);
}
(3)终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的 值,例如:List、Integer,甚至是 void 。
-
●查找与匹配
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭 代,称为外部迭代。 相反,Stream API 使用内部 迭代——它帮你把迭代做了) |
public class TestStreamAPI3 {
List<User> users = Arrays.asList(
new User("zhangsan",18,999.99, User.Status.FREE),
new User("lisi",38,999.99, User.Status.WORK),
new User("wangwu",50,999.99, User.Status.VOCATION),
new User("zhaoliu",16,999.99, User.Status.WORK),
new User("tianqi",8,999.99, User.Status.VOCATION),
new User("tianqiq",8,999.99, User.Status.FREE)
);
//---------------------------------------------查找与匹配
/*
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值*/
@Test
public void test1(){
//allMatch()
boolean b1 = users.stream()
.allMatch((u) -> u.getStatus().equals(User.Status.FREE));
System.out.println(b1);
//anyMatch
boolean b2 = users.stream()
.anyMatch((u) -> u.getStatus().equals(User.Status.FREE));
System.out.println(b2);
//noneMatch
boolean b3 = users.stream()
.noneMatch((user) -> user.getStatus().equals(User.Status.FREE));
System.out.println(b3);
//findFirst:将有可能为空的值封装到Optional中
Optional<User> first = users.stream()
.sorted((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()))
.findFirst();
System.out.println(first.get());
//findAny
Optional<User> any = users.parallelStream()
.filter((u) -> u.getStatus().equals(User.Status.FREE))
.findAny();
System.out.println(any.get());
//count
long count = users.stream()
.count();
System.out.println(count);
//max
Optional<User> max = users.stream()
.max((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()));
System.out.println(max.get());
Optional<Integer> min = users.stream()
.map(User::getAge)
.min(Integer::compareTo);
System.out.println(min.get());
}
}
-
●归约
方法 | 描述 |
---|---|
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 T 第一个参数是 一个起始值 |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。 返回 Optional<T> |
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它 来进行网络搜索而出名
@Test
public void test2(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer reduce = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(reduce);
//员工的工资和
Optional<Double> reduce1 = users.stream()
.map(User::getSalary)
.reduce(Double::sum);
System.out.println(reduce1.get());
}
-
●收集
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的 实现, 用于给Stream中元素做汇总的方法 |
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
方法 | 返回类型 | 作用 |
---|---|---|
toList() | List<T> | 把流中元素收集到List |
List<Employee> emps= list.stream().collect(Collectors.toList()); | ||
toSet() | Set<T> | 把流中元素收集到Set |
Set<Employee> emps= list.stream().collect(Collectors.toSet()); | ||
toCollection() | Collection<T> | 把流中元素收集到创建的集合 |
Collection<Employee> emps=list.stream().collect(Collectors.toCollection(ArrayList::new)); | ||
counting() | Long | 计算流中元素的个数 |
long count = list.stream().collect(Collectors.counting()); | ||
averagingInt() averagingDouble() averagingLong() | Double | 计算流中元素Integer、double、long属性的平均值 |
double avg= list.stream().collect(Collectors.averagingInt(Employee::getSalary)); | ||
summingInt() summingDouble() summingLong() | Integer Double Long | 对流中元素的Integer\ double \ long属性求和 |
int total=list.stream().collect(Collectors.summingInt(Employee::getSalary)); | ||
summarizingInt() summarizingDouble() SummarizingLong() | IntSummaryStatistics DoubleSummaryStatistics LongSummaryStatistics | 收集流中Integer属性的统计值。 如:平均值 |
IntSummaryStatistics iss= list.stream().collect(Collectors.summarizingInt(Employee::getSalary)) | ||
maxBy() | Optional<T> | 根据比较器选择最大 |
Optional<Emp> max= list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); | ||
minBy() | Optional<T> | 根据比较器选择最小值 |
Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); | ||
reducing | 归约产生的类型 | 从一个作为累加器的初始值 开始,利用BinaryOperator与 流中元素逐个结合,从而归 约成单个 |
int total=list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); | ||
collectingAndThen | 转换函数返回的类型 | 包裹另一个收集器,对其结 果转换函数 |
inthow= list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); | ||
groupingBy | Map<K, List<T>> | 根据某属性值对流分组,属 性为K,结果为 |
Map<Emp.Status, List<Emp>> map= list.stream() .collect(Collectors.groupingBy(Employee::getStatus)); //多级分组 先按状态分,再按年龄段分 Map<User.Status, Map<String, List<User>>> map1 = list.stream .collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy( (u) ->{ if(((User) u).getAge() <= 35){ return "青年"; }else if(((User) u).getAge() <=50){ return "中年"; }else{ return "老年"; } }))); | ||
partitioningBy | Map<Boolean, List<T>> | 根据true或false进行分区 |
Map<Boolean, List<User>> map = list.stream().collect(Collectors.partitioningBy(u) -> u.getAge() >35)); | ||
joining | String | 连接流中每个字符串 |
String str= list.stream().map(Employee::getName).collect(Collectors.joining()); //第一个参数:以...分隔,第二个参数:前缀,第三个参数:后缀 String str= list.stream().map(Employee::getName).collect(Collectors.joining("," , "===" , "===")); |
public class TestStreamAPI3 {
List<User> users = Arrays.asList(
new User("zhangsan",18,999.99, User.Status.FREE),
new User("lisi",38,999.99, User.Status.WORK),
new User("wangwu",50,999.99, User.Status.VOCATION),
new User("zhaoliu",16,999.99, User.Status.WORK),
new User("tianqi",8,999.99, User.Status.VOCATION),
new User("tianqiq",8,999.99, User.Status.FREE),
new User("tianqiq",8,999.99, User.Status.FREE)
);
//---------------------------------------------查找与匹配
/*
allMatch(Predicate p) 检查是否匹配所有元素
anyMatch(Predicate p) 检查是否至少匹配一个元素
noneMatch(Predicate p) 检查是否没有匹配所有元素
findFirst() 返回第一个元素
findAny() 返回当前流中的任意元素
count() 返回流中元素总数
max(Comparator c) 返回流中最大值
min(Comparator c) 返回流中最小值*/
@Test
public void test1(){
//allMatch()
boolean b1 = users.stream()
.allMatch((u) -> u.getStatus().equals(User.Status.FREE));
System.out.println(b1);
//anyMatch
boolean b2 = users.stream()
.anyMatch((u) -> u.getStatus().equals(User.Status.FREE));
System.out.println(b2);
//noneMatch
boolean b3 = users.stream()
.noneMatch((user) -> user.getStatus().equals(User.Status.FREE));
System.out.println(b3);
//findFirst:将有可能为空的值封装到Optional中
Optional<User> first = users.stream()
.sorted((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()))
.findFirst();
System.out.println(first.get());
//findAny
Optional<User> any = users.parallelStream()
.filter((u) -> u.getStatus().equals(User.Status.FREE))
.findAny();
System.out.println(any.get());
//count
long count = users.stream()
.count();
System.out.println(count);
//max
Optional<User> max = users.stream()
.max((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge()));
System.out.println(max.get());
Optional<Integer> min = users.stream()
.map(User::getAge)
.min(Integer::compareTo);
System.out.println(min.get());
}
//-----------------------------------归约---------------------
/*
reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回 T 第一个参数是起始值*/
@Test
public void test2(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer reduce = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(reduce);
Optional<Double> reduce1 = users.stream()
.map(User::getSalary)
.reduce(Double::sum);
System.out.println(reduce1.get());
}
//---------------------------------------------收集---------------
/*collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的 实现,用于给Stream中元素做汇总的方法*/
@Test
public void test3(){
users.stream()
.map(User::getName)
.collect(Collectors.toList())
.forEach(System.out::println);
System.out.println("-------------------------------------");
users.stream()
.map(User::getName)
.collect(Collectors.toSet())
.forEach(System.out::println);
System.out.println("---------------------------------------");
users.stream()
.map(User::getName)
.collect(Collectors.toCollection(HashSet::new))
.forEach(System.out::println);
}
@Test
public void test4(){
//总数
Long collect = users.stream()
.collect(Collectors.counting());
System.out.println(collect);
//平均值
Double collect1 = users.stream()
.collect(Collectors.averagingDouble(User::getSalary));
System.out.println(collect1);
//工资总和
Double collect2 = users.stream()
.collect(Collectors.summingDouble(User::getSalary));
System.out.println(collect2);
Collectors.summa
//最大年龄的员工
Optional<User> collect3 = users.stream()
.collect(Collectors.maxBy((u1, u2) -> Integer.compare(u1.getAge(), u2.getAge())));
System.out.println(collect3.get());
//最小年龄
Optional<Integer> collect4 = users.stream()
.map(User::getAge)
.collect(Collectors.minBy(Integer::compare));
System.out.println(collect4.get());
}
@Test
public void test5(){
//按照状态分组 Map沒有foreach
Map<User.Status, List<User>> map = users.stream()
.collect(Collectors.groupingBy(User::getStatus));
System.out.println(map);
}
//多级分组 先按状态分,然后按年龄段分
@Test
public void test6(){
Map<User.Status, Map<String, List<User>>> collect = users.stream()
.collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy((u) -> {
if (((User) u).getAge() <= 35) {
return "青年";
} else if (((User) u).getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(collect);
}
//根据true或false进行分区
@Test
public void test7(){
Map<Boolean, List<User>> collect = users.stream()
.collect(Collectors.partitioningBy((u) -> u.getAge() > 35));
System.out.println(collect);
}
//summarizingInt
@Test
public void test8(){
DoubleSummaryStatistics dss = users.stream()
.collect(Collectors.summarizingDouble(User::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getAverage());
System.out.println(dss);
}
//joining
@Test
public void test9(){
String collect = users.stream()
.map(User::getName)
.collect(Collectors.joining());
System.out.println(collect);
String collect1 = users.stream()
.map(User::getName)
.collect(Collectors.joining(",", "===", "==="));
}
}
3、Stream API小练习
public class Trader {
private String name;
private String city;
//省略get、set、toString()
}
public class Transaction {
private Trader trader;
private int year;
private int value;
//省略get set toString()
}
public class TestStreamAPI4 {
/*
1、给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?
给定【1,2,3,4,5】 应该返回【1,4,9,16,25】
*/
@Test
public void test1(){
Integer[] integers = {1, 2, 3, 4, 5};
Arrays.stream(integers)
.map( ( x ) -> x * x)
.forEach(System.out::println);
}
/*
2、怎么用map和reduce方法数一数流中有多少个User呢?
*/
@Test
public void test2(){
List<User> users = Arrays.asList(
new User("zhangsan",18,999.99, User.Status.FREE),
new User("lisi",38,999.99, User.Status.WORK),
new User("wangwu",50,999.99, User.Status.VOCATION),
new User("zhaoliu",16,999.99, User.Status.WORK),
new User("tianqi",8,999.99, User.Status.VOCATION),
new User("tianqiq",8,999.99, User.Status.FREE),
new User("tianqiq",8,999.99, User.Status.FREE)
);
Optional<Integer> reduce = users.stream()
.map((u) -> 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 test3(){
transactions.stream()
.filter( (t) -> t.getYear() ==2011)
.sorted( ( t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()) )
.forEach(System.out::println);
}
//2、交易员都在哪些不同的城市工作过
@Test
public void test4(){
transactions.stream()
.map( ( t ) -> t.getTrader().getCity())
.distinct()//去重
.forEach(System.out::println);
}
//3、查找所有来自剑桥的交易员,并按姓名排序
@Test
public void test5(){
transactions.stream()
.filter( ( t ) -> t.getTrader().getCity().equals("Cambridge") )
.map(Transaction::getTrader) //取出交易员
.sorted( ( t1, t2) -> t1.getName().compareTo(t2.getName()) )
.distinct()
.forEach(System.out::println);
}
//4、返回所有交易员的姓名字符串,按字母顺序排序
@Test
public void test6(){
transactions.stream()
.map(( t ) -> t.getTrader().getName())
.sorted()
.forEach(System.out::println);
System.out.println("------------------------------------------------");
String str = transactions.stream()
.map((t) -> t.getTrader().getName())
.sorted()
.reduce("", String::concat); //拼成一个字符串
System.out.println(str);
System.out.println("==================================");
//把名字中的所有字母排序
transactions.stream()
.map((t) -> t.getTrader().getName())
.flatMap(TestStreamAPI4::strHandler)
.sorted( ( s1, s2) -> s1.compareToIgnoreCase(s2))//忽略大小写的比较
.forEach(System.out::print);
}
public static Stream<String> strHandler(String str){
List<String> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c.toString());
}
return list.stream();
}
//5、有没有交易员是在米兰工作的
@Test
public void test7(){
boolean milan = transactions.stream()
.anyMatch((t) -> t.getTrader().getCity().equals("Milan"));
System.out.println(milan);
}
//6、打印生活在剑桥的交易员的所有交易额
@Test
public void test8(){
Optional<Integer> cambridge = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(cambridge.get());
}
//7、所有交易中 最高的交易额是多少
@Test
public void test9(){
Optional<Integer> max = transactions.stream()
.map(Transaction::getValue)
.max(Integer::compare);
System.out.println(max.get());
}
//8、找到交易额最小的交易
@Test
public void test10(){
Optional<Transaction> max = transactions.stream()
.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
System.out.println(max.get());
}
}