一、前言
Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。
Java8 新增了非常多的特性,我们主要讨论以下几个:
- Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
- 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
- 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
- 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
- Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API − 加强对日期与时间的处理。
- Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
- Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
二、Lambda表达式
1、语法:
语法格式一:无参数,无返回值 () -> System.out.println(“Hello Lambda!”);
语法格式二:有一个参数,并且无返回值 (x) -> System.out.println(x);
语法格式三:若只有一个参数,小括号可以省略不写 x -> System.out.println(x);
语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 Comparator com = (x, y) -> {System.out.println(“函数式接口”); return Integer.compare(x, y); };
语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 Comparator com = (x, y) -> Integer.compare(x, y);
2、为什么使用lambda表达式
- 避免匿名内部类定义过多
- 可以让你的代码看起来很简洁
- 去掉了一堆没有意义的代码,只留下核心的逻辑
3、lambda.java示例:
public class lambdaTest {
//2.静态内部类
static class Like2 implements ILike {
@Override
public void like(int a) {
System.out.println("I like lambda " + a);
}
}
public static void main(String[] args) {
ILike like2 = new Like2();
like2.like(2);
//3.局部内部类
class Like3 implements ILike {
@Override
public void like(int a) {
System.out.println("I like lambda " + a);
}
}
ILike like3 = new Like3();
like3.like(3);
//4.匿名内部类
ILike like4 = new ILike() {
@Override
public void like(int a) {
System.out.println("I like lambda " + a);
}
};
like4.like(4);
//5 lambda
ILike like5 = (a) -> {
System.out.println("I like lambda " + a);
};
like5.like(5);
//简化
ILike like6 = a -> System.out.println("I like lambda " + a);
like5.like(6);
}
//总结:1、lambda表达式的前提必须是函数式接口
//函数式接口:注解@FunctionalInterface
//入参或逻辑结构只有一个的话,(),入参的类型和{}都可以省略
}
//定义接口
interface ILike {
void like(int a);
//void like(String b);
default void like2() {
System.out.println("sssssss");
}
@Override
String toString();
}
//实现类
class Like1 implements ILike {
@Override
public void like(int a) {
System.out.println("I like lambda " + a);
}
}
三、stream
1、流式操作
不是一个数据结构,不负责任何的数据存储。更像是一个迭代器,有序地获取到数据源中的每一个数据,并且可以对这些数据进行一些操作。流式操作的每一个方法,返回值都是返回的流本身。
2、使用stream的三个步骤
第一步:获取数据源:集合、数组
(1)创建 Person对象
@Data
public class Person {
private String name;
private int age;
private int score;
public Person(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
public Person(){
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
(2)创建Data.java
public class Data {
public static List<Person> getData() {
List<Person> list = new ArrayList<>();
list.add(new Person("小李",15,80));
list.add(new Person("小王",16,90));
list.add(new Person("小明",13,100));
list.add(new Person("小赵",12,70));
list.add(new Person("小许",11,60));
list.add(new Person("小张",14,59));
list.add(new Person("小刘",10,95));
return list;
}
}
(3)获取数据源
//1.获取数据源:
Stream<Person> s = Data.getData().stream();
第二步:对数据进行处理的过程:过滤、排序、映射……(中间操作)
//中间操作1:filter
//filter:是一个过滤器,定义一个条件,把符合条件的数据留下来
//需求:保留集合中成绩大于80的人的信息
s.filter(ele -> ele.getScore() >80).forEach(System.out::println);
//中间操作2:distinct
//distinct:去重,去除集合中重复的数据
//去重规则:
// (1)先判断hashCode()
// (2)hashCode相同时才去判断equal()
s.distinct().forEach(System.out::println);
//中间操作3:sorted
//sorted:排序,对流中的元素进行排序
//sorted():要求流中的元素对应的类需要实现Comparable 接口
//public class Person implements Comparable<Person>
s.sorted().forEach(System.out::println);
//Data.getData().stream().sorted(Comparator<T> c):使用自定义的规则来进行排序
//需求:将集合中的人按照年龄升序的规则排序
s.sorted((ele1,ele2) -> ele1.getAge() - ele2.getAge()).forEach(System.out::println);
//中间操作4:limit
//limit:限制,只取流中指定位的元素
s.limit(3).forEach(System.out::println);
//中间操作5:skip
//skip:跳过
s.skip(3).forEach(System.out::println);
//需求:已知集合中有七个元素,取出第2~5个元素
s.skip(1).limit(4).forEach(System.out::println);
//中间操作6:map
//map:映射
//需求:将流中的Person对象替换成他们的名字
//s.map(ele -> ele.getName()).forEach(System.out::println);
s.map(ele -> ele.getScore() >80 ? ele : ele.getName()).forEach(System.out::println);
第三步:对流中数据的整合:转成集合、数组……(最终操作)
//最终操作1:collect
// 转成List
List<Person> list = s.collect(Collectors.toList());
//转成Set
Set<Person> collect = s.collect(Collectors.toSet());
//转成Map
Map<Integer, Integer> map = s.collect(Collectors.toMap(ele1 -> ele1.getScore(), ele2 -> ele2.getAge()));
System.out.println(map);
//Map<String, Integer> map = s.collect(Collectors.toMap(Person::getName, Person::getScore));
//最终操作2:reduce
//将Stream中的值计算得到一个最终结果
//需求:求若干个数字的和
Stream<Integer> stream = Stream.of(1,2,3,4,5);
Optional<Integer> reduce = stream.reduce((n1, n2) -> n1 + n2);
System.out.println(reduce.get());
//需求:求集合中存储的若干Person的成绩和
Person tmp = new Person();
Optional<Person> reduce = Data.getData().stream().reduce((ele1, ele2) -> tmp.setScore(ele1.getScore() + ele2.getScore()));
System.out.println(reduce.get().getScore());
//最终操作3:max,min
//需求:找到集合中成绩最高的人的信息
Person max = s.max((ele1, ele2) -> ele1.getScore() - ele2.getScore()).get();
System.out.println(max);
//需求:找到集合中年龄最小的人的信息
Person min = s.min((ele1, ele2) -> ele1.getAge() - ele2.getAge()).get();
System.out.println(min);
//最终操作4:anyMatch、allMatch、noneMatch
//需求1:判断集合中是否有成绩大于80的人
boolean any = s.anyMatch(ele -> ele.getScore() > 80);
System.out.println(any);
//需求2:判断集合中的人是否全部及格
boolean all = s.allMatch(ele -> ele.getScore() >= 60);
System.out.println(all);
boolean none = s.noneMatch(ele -> ele.getScore() < 60);
System.out.println(none);
//最终操作5:count
long count = s.count();
System.out.println(count);
//最终操作6:foreach
//s.forEach(ele -> System.out.println(ele));
s.forEach(System.out::println);
Collector 工具类:提供若干个方法,返回一个Collector接口的实现类对象
//toList,toSet,toMap
//maxBy:通过指定的规则,获取流中最大的元素
//minBy:通过指定的规则,获取流中最小的元素
System.out.println(Data.getData().stream().collect(Collectors.maxBy((ele1,ele2) -> ele1.getScore() - ele2.getScore())));
System.out.println(Data.getData().stream().collect(Collectors.minBy((ele1,ele2) -> ele1.getScore() - ele2.getScore())));
//joining:合并,将流中的元素以字符串的形式拼接起来
//需求:将集合中所有的Person对象的姓名拼接成一个字符串
String res1 = Data.getData().stream().map(Person::getName).collect(Collectors.joining());
System.out.println(res1);
String res2 = Data.getData().stream().map(Person::getName).collect(Collectors.joining("-"));
System.out.println(res2);
String res3 = Data.getData().stream().map(Person::getName).collect(Collectors.joining("-","@","@"));
System.out.println(res3);
//summingInt:将流中的元素映射成一个int类型的元素,最后进行求和
//需求:将集合中所有的人的成绩求和
System.out.println(Data.getData().stream().collect(Collectors.summingInt(Person::getScore)));
//averagingInt:将流中的元素映射成一个int类型的元素,最后求平均值
System.out.println(Data.getData().stream().collect(Collectors.averagingInt(Person::getScore)));
//summarizingInt:将流中的元素映射成一个int类型的元素,最后获取这些元素的描述信息
IntSummaryStatistics intSummaryStatistics = Data.getData().stream().collect(Collectors.summarizingInt(Person::getScore));
System.out.println(intSummaryStatistics.getMax());
System.out.println(intSummaryStatistics.getAverage());
System.out.println(intSummaryStatistics.getCount());
System.out.println(intSummaryStatistics.getMin());
System.out.println(intSummaryStatistics.geSum());
并行流:把一个内容分成多个数据块,使用不用的线程分别处理每个数据块的流。
//写法一:
Data.getData().stream().parallel();
//写法二:
Data.getData().parallelStream();
//例子:计算0~500亿的总和
long start = System.currentTimeMillis();
LongStream.rangeClosed(0L, 50000000000L).reduce(Long::sum);
long end = System.currentTimeMillis();
System.out.println(end - start);