1.声明
本人参考的视频为:https://www.bilibili.com/video/av62117143?from=search&seid=11081886781361585823
只看了其中的stream部分,视频内部有练习题,加强训练的可以去做。
2.基础知识
一、 lambda表达式
lambda 表达式的基础语法:Java8中引入了一个新的操作符 “->” 该操作符称为箭头操作符或lambda操作符 “->” 箭头操作符将lambda表达式拆分成两部分:
左侧: lambda 表达式的参数列表
右侧:lambda 表达式中所需执行的功能,即lambda体
- 语法格式一:无参数,无返回值 () -> System.out.println(“Hello lambda!”);
@Test
public void test_1() {
Runnable r = new Runnable() {
public void run() {
System.out.println("Hello World!");
}
};
r.run();
System.out.println("-------------------------------");
Runnable r1 = () -> System.out.println("Hello Lambda!");
r1.run();
}
- 语法格式二:一个参数,无返回值 (x) -> System.out.println(x);
@Test
public void test_2() {
Consumer<String> con = (x) -> System.out.println(x);
con.accept("this is a message!");
}
-
语法格式三:若只有一个参数,小括号可以省略不写 x -> System.out.println(x);
-
语法格式四:两个以上参数,有返回值,lambda有多条语句
Comparator com = (x,y) -> {
System.out.println(“函数式接口”);
return Integer.compare(x, y);
};
@Test
public void test_4() {
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
- 语法格式五:两个以上参数,有返回值,lambda有一条语句,大括号和return可以省略 Comparator com
= (x, y) -> Integer.compare(x, y);
@Test
public void test_5() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}
- 语法格式六:lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器可以通过上下文推断出数据类型,即“类型推断”
Comparator com = (Integer x, Integer y) ->
Integer.compare(x, y);
@Test
public void test_6() {
Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
}
- 示例
// 需求:对一个数进行运算
@Test
public void test_7() {
// 其实就是参数和实现方法的集合
System.out.println(operation(100, (x) -> x * x));
System.out.println(operation(200, (y) -> y + 200));
}
public Integer operation(Integer num, MyFun mf) {
return mf.getValue(num);
}
-
结论一、左右遇一括号省,左侧推断类型省。
-
结论二、lambda 表达是需要“函数式”接口的支持
-
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface修饰 可以检查是否是函数式接口
下面是自定义的函数式接口(注:函数是接口仅仅定义的是入参是什么,出参是什么,具体的实现方式是lambda表达式,及调用函数式接口的形参)
package com.example.demo.ConsoleTest.Java8;
@FunctionalInterface
public interface MyFun {
//该接口仅仅定义的出参和入参的格式
public Integer getValue(Integer num);
}
上面函数式接口的使用
// 需求:对一个数进行运算
@Test
public void test_7() {
// 其实就是参数和实现方法的集合
System.out.println(operation(100, (x) -> x * x));
System.out.println(operation(200, (y) -> y + 200));
}
public Integer operation(Integer num, MyFun mf) {
//对函数是接口的调用
return mf.getValue(num);
}
输出为:
10000
400
解释:看上去挺复杂,其实operation 仅仅是将函数是接口getValue的入参和实现方式结合起来的工具
函数式接口有了入参和实现方式,计算结果进行返回,其实就是将入参和实现方式拆解开来,灵活实现,相对于传统的接口更加灵活节省空间!!!
二、Java8内置的四大核心函数式接口
- Consumer: 消费型接口 void accept(T t);
@Test
public void test_1() {
happy(1000, (m) -> System.out.println("今晚消费" + m + "元"));// 第二个参数是对Consumer接口内部方法的实现
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
- Supplier:供给型接口 T get();
@Test
public void test_2() {
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
// 需求:产生指定个数的整数,并放入到集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
while (num-- >= 0) {
list.add(sup.get());
}
return list;
}
- Function<T, R>: 函数型接口 R apply(T t);
@Test
public void test_3() {
System.out.println(changeString("abcdefghijklmnopq",(str)->str.length()) );
}
// 需求:处理一些字符串
public Integer changeString(String temp, Function<String, Integer> function) {
return function.apply(temp);
}
- Predicate: 断言型接口: boolean test(T t);
@Test
public void test_4() {
System.out.println(judgeString("sdhk",(str)->str.length()==12));
}
//需求:判断是否有12个字符
public Boolean judgeString(String temp,Predicate<String> pre) {
return pre.test(temp);
}
- Java8中还提供了其他函数式接口,可以自行搜索运用
三、引用 - 方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用“引用方法”(可以理解为方法引用是Lambda表达式的另外一种表现形式)
- ① 对象 :: 实例方法名
@Test
public void test_1() {
PrintStream ps = System.out;
Consumer<String> con = (x) -> ps.println(x);
con.accept("abcdefg");
Consumer<String> con1 = ps::println;
con1.accept("xxxxxx");
}
@Test
public void test_2() {
Entity entity = new Entity();
Supplier<String> sup = () -> entity.getName();
String str = sup.get();
System.out.println(str);
Supplier<Integer> sup2 = entity::getAge;
Integer num = sup2.get();
System.out.println(num);
}
- ② 类 :: 静态方法名
@Test
public void test_3() {
// Lambda
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
int res = com.compare(2, 0);
System.out.println(res);
// 方法引用
Comparator<Integer> com2 = Integer::compare;
int res2 = com2.compare(1, 3);
System.out.println(res2);
}
- ③ 类 :: 实例方法名
@Test
public void test_4() {
// lambda
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
boolean flag = bp.test("hello", "world");
System.out.println(flag);
// 方法引用
BiPredicate<String, String> bp2 = String::equals;
boolean flag2 = bp2.test("hello", "world");
System.out.println(flag2);
}
-
注意:
-
①lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致
-
②若lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用类 :: 实例方法名
-
2.构造器引用
-
格式:ClassName::new
-
注意:需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表保持一致,系统会自动去匹配!
@Test
public void test_5(){
//0参数
Supplier<Entity> sup = () -> new Entity();
System.out.println(sup.get());
//构造器引用方式
Supplier<Entity> sup2 = Entity::new;
Entity entity = sup2.get();
System.out.println(entity);
//1参数
Function<Integer,Entity> fun = (x) -> new Entity(x);
System.out.println(fun.apply(1).getId());
Function<Integer,Entity> fun2 = Entity::new;
System.out.println(fun2.apply(2).getId());
//2参数
BiFunction<Integer,Integer,Entity> bf = Entity::new;
System.out.println(bf.apply(1, 1).getId()+"====="+bf.apply(1, 1).getAge());
}
- 3.数组引用 Type[]::new
@Test
public void test_6() {
//lambda
Function<Integer,String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
//数组引用
Function<Integer,String[]> fun2 = String[]::new;
System.out.println(fun2.apply(20).length);
}
3.stream流操作
Stream的三个操作步骤:创建 Stream、中间操作、终止操作(终端操作)多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为惰性求值
- 1.创建 Stream
@Test
public void test_1() {
// 可以通过Collection系列集合提供的stream() 或 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
// 2.通过Arrays中的静态方法 stream() 获取数组流
Entity[] entitys = new Entity[10];
Stream<Entity> stream2 = Arrays.stream(entitys);
// 3.通过stream类中的静态方法 of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
// 创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEachOrdered(System.out::println);
// 生成
Stream.generate(() -> Math.random()).limit(10).forEach(System.out::println);
;
}
- 2.中间操作
public List<Entity> Initialization() {
List<Entity> list = new ArrayList<>();
list.add(new Entity(1, "zhang", 25));
list.add(new Entity(2, "wang", 26));
list.add(new Entity(3, "li", 27));
list.add(new Entity(4, "zhao", 28));
list.add(new Entity(5, "qian", 29));
list.add(new Entity(6, "sun", 30));
list.add(new Entity(7, "li", 31));
list.add(new Entity(8, "zhou", 32));
list.add(new Entity(9, "wu", 33));
list.add(new Entity(9, "wu", 33));
list.add(new Entity(9, "wu", 33));
list.add(new Entity(9, "wu", 33));
list.add(new Entity(9, "wu", 33));
list.add(new Entity(9, "wu", 33));
return list;
}
- 筛选与切片 filter–接受lambda,从流中排除某些元素 limit–截断流,使其元素不超过给定数量。
@Test
public void test_2() {
List<Entity> list = Initialization();
// 中间操作:不会执行任何操作
Stream<Entity> stream = list.stream().filter((e) -> e.getId() > 5);
// 终止操作:一次性执行全部内容,即"惰性求值"
stream.forEach(System.out::println);
}
- skip(n)–跳过元素,返回一个扔掉前n个元素的流,若流中元素不足n个,则返回一个空流,与limit(n)互补
@Test
public void test_5() {
Initialization().stream().filter((e) -> e.getAge() > 25).skip(2).forEach(System.out::println);
}
- distinct–筛选,通过流所生成元素的hashcode()和equals()去除重复元素
(也就是说要在实体中生成hashcode和equals)
@Test
public void test_6() {
Initialization().stream().filter((e) -> e.getAge() > 25).skip(2).distinct().forEach(System.out::println);
}
- 映射
map–接受lambda,将元素转换成其他形式或提取信息,接受一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素。
@Test
public void test_7() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
list.stream().map((str) -> str.toUpperCase()).forEach(System.out::println);
Initialization().stream().map((x) -> x.getId() * 100).forEach(System.out::println);
}
- flat Map–接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有的流连接成一个流
@Test
public void test_8() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
Stream<Stream<Character>> stream = list.stream().map(java8_5::filterCharacter);
stream.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("=================================================");
list.stream().flatMap(java8_5::filterCharacter).forEach(System.out::println);
}
- sorted(comparable) --自然排序 sorted(Coparator com) --定制排序 -号表示倒着排
@Test
public void test_9() {
List<String> list = Arrays.asList("ccc", "eee", "aaa", "bbb", "ddd", "fff");
list.stream().sorted().forEach(System.out::println);
System.out.println("========================================================");
Initialization().stream().sorted((e1, e2) -> {
if (e1.getName().equals(e2.getName())) {
return -e1.getAge().compareTo(e2.getAge());
} else {
return -e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
;
}
3.终止操作
- 查找与匹配
- allMatch——检查是否匹配所有元素
- anyMatch——检查是否至少匹配一个元素
- noneMatch——检查是否没有匹配的元素
- findFirst——返回第一个元素
- findAny——返回当前流中的任意元素
- count——返回流中元素的总个数
- max——返回流中最大值
- min——返回流中最小值
@Test
public void test_10() {
System.out.println(Initialization().stream().allMatch(e -> e.getAge() > 25));
System.out.println(Initialization().stream().anyMatch(e -> e.getAge() > 25));
System.out.println(Initialization().stream().noneMatch(e -> e.getAge() > 25));
// Optional 防止空指针异常的容器,如果流中没有元素,那么findFirst就会出现空指针异常,如果返回为空,那么容器就会有个新的对象来替换
Optional<Entity> en1 = Initialization().stream().findFirst();
Optional<Entity> en2 = Initialization().stream().findAny();
Optional<Entity> en3 = Initialization().stream().max((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
Optional<Entity> en4 = Initialization().stream().min((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
Optional<Integer> a = Initialization().stream().map(Entity::getAge).min(Double::compare);
System.out.println(en1.get());
System.out.println(en2.get());
System.out.println(Initialization().stream().count());
System.out.println(en3.get());
System.out.println(en4.get());
System.out.println(a.get());
}
- 归纳
- reduce(T identity,BinaryOperator) /
reduce(BinaryOperator)可以将流中元素反复结合起来,得到一个值。
@Test
public void test_11() {
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer l = list1.stream().reduce(5, (x, y) -> x + y);
System.out.println(l);
List<String> list2 = Arrays.asList("ccc", "eee", "aaa", "bbb", "ddd", "fff");
Optional<String> i = list2.stream().reduce((x, y) -> x + y);
System.out.println(i.get());
System.out.println("===========================================");
Optional<Integer> j = Initialization().stream().map(Entity::getAge).reduce(Integer::sum);
System.out.println(j.get());
}
- 收集
- collect – 将流转换为其他形式,接受一个collector接口的实现,用stream中元素做汇总的方法
@Test
public void test_12() {
List<Integer> list = Initialization().stream().map(Entity::getAge).collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("===============================");
Set<String> set = Initialization().stream().map(Entity::getName).collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("=================================");
HashSet<String> hs = Initialization().stream().map(Entity::getName)
.collect(Collectors.toCollection(HashSet::new));
hs.forEach(System.out::println);
// 个数
Long count = Initialization().stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("=================================");
// 平均值
Double avg = Initialization().stream().collect(Collectors.averagingDouble(Entity::getAge));
System.out.println(avg);
// 总和
Integer sum = Initialization().stream().collect(Collectors.summingInt(Entity::getAge));
System.out.println(sum);
// 最大值
Optional<Entity> max = Initialization().stream()
.collect(Collectors.maxBy((x, y) -> Integer.compare(x.getAge(), y.getAge())));
System.out.println(max.get());
Optional<Integer> Max = Initialization().stream().map(Entity::getAge)
.collect(Collectors.maxBy((x, y) -> Integer.compare(x, y)));
System.out.println(Max.get());
// 最小值
Optional<Integer> min = Initialization().stream().map(Entity::getAge)
.collect(Collectors.minBy((x, y) -> Integer.compare(x, y)));
System.out.println(min.get());
//综合
DoubleSummaryStatistics Summary = Initialization().stream().collect(Collectors.summarizingDouble(Entity::getAge));
System.out.println("综合"+Summary.getSum());
System.out.println("综合"+Summary.getAverage());
System.out.println("综合"+Summary.getCount());
System.out.println("综合"+Summary.getMax());
System.out.println("综合"+Summary.getMin());
System.out.println("==================================================");
// 分组
Map<String, List<Entity>> map = Initialization().stream().collect(Collectors.groupingBy(Entity::getName));
map.forEach((x, y) -> System.out.println(x + "==" + y));
System.out.println("================================================");
Map<Integer, List<Entity>> map2 = Initialization().stream().collect(Collectors.groupingBy(Entity::getAge));
map2.forEach((x, y) -> System.out.println(x + "=" + y));
System.out.println("=================================================");
// 多几分组
Map<String, Map<String, List<Entity>>> map3 = Initialization().stream()
.collect(Collectors.groupingBy(Entity::getName, Collectors.groupingBy((e) -> {
if (e.getAge() < 22) {
return "青年";
} else if (e.getAge() < 24) {
return "中年";
} else {
return "老年";
}
})));
map3.forEach((x, y) -> y.forEach((a, b) -> System.out.println(x + "===" + y + "===" + a + "======" + b)));
System.out.println("************************************************************************************");
//分区
Map<Boolean,List<Entity>> map4 = Initialization().stream().collect(Collectors.partitioningBy((e) -> e.getAge() >30));
map4.forEach((x,y) -> System.out.println(x+"====="+y));
System.out.println("======================================================================================");
//连接字符串
String str = Initialization().stream().map(Entity::getName).collect(Collectors.joining("==="));
System.out.println(str);
String str1 = Initialization().stream().map(Entity::getName).collect(Collectors.joining("=","****","///"));
System.out.println(str1);
}
https://download.csdn.net/my相关demo下载