1. Java8新特性简介
2. Java8新特性好处
- 速度更快
- 代码更少(增加了新特性Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常:Optional
- Nashron引擎,允许在JVM上运行JS应用
3. Lambda表达式
3.1 Lambda表达式的使用
- 举例: ( o1, o2) -> Integer.compare(o1,o2);
- 格式:
-> :lambda操作符 或箭头操作符 ->左边:lambad形参列表,(其实就是接口中的抽象方法的形参列表) ->右边:lambda体 (其实就是重写的抽象方法的方法体) - lambda表达式使用: (分6种情况)
总结:->左边,lambda形参列表的参数类型可以省略(类型推断), 如果lambda形参列表只有一个参数,其一对()小括号也可以省略 如果有没有或这有2个以上的,就不要省了 ->右边:lambda应该使用一对{}包裹,如果lambda体只有一条执行语句(可能是return语句) 可以省略这一对{}和return关键字 - lambda表达式本质:作为函数式接口的实例
- 如果一个接口中,只声明了一个抽象方法,则此接口就成为函数式接口
- 所以以前用匿名实现类表示的,现在都可以用lambda表达式来写。
3.1.1 语法格式一:无参,无返回值
public static void test1(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("我爱北京故宫");
}
};
r1.run();
Runnable r2 = () -> {System.out.println("我爱北京天安门");};
r2.run();
}
3.1.2 语法格式二:需要一个参数,但是没有返回值
public static void test2(){
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("谎言和誓言区别是什么呢?");
System.out.println("****************************");
Consumer<String> con2 = (String s) -> {
System.out.println(s);
};
con2.accept("一个是听的人当真了,一个是说的人当真了");
}
3.1.3 语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为“类型推断”
public static void test3(){
Consumer<String> con2 = (String s) -> {
System.out.println(s);
};
con2.accept("一个是听的人当真了,一个是说的人当真了");
Consumer<String> con3 = (s) -> {
System.out.println(s);
};
con3.accept("一个是听的人当真了,一个是说的人当真了");
ArrayList<String> list = new ArrayList<>();
int [] arr = new int[]{1,2,3};
int [] bb = {1,2,3};
}
3.1.4 语法格式四:Lambda若只需要一个参数时,参数 的小括号可以省略
public static void test4 (){
Consumer<String> con3 = (s) -> {
System.out.println(s);
};
con3.accept("一个是听的人当真了,一个是说的人当真了");
Consumer<String> con4 = s -> {
System.out.println(s);
};
con4.accept("一个是听的人当真了,一个是说的人当真了");
}
3.1.5 语法格式五:Lambda需要两个或以上的参数,多条执行语句,并且有返回值
public static void test5(){
Comparator<Integer> com1= new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(com1.compare(11,12));
System.out.println("**************");
Comparator<Integer> com2 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(11,12));
}
3.1.6 语法格式六:当Lambda体只有一条语句时,return与大括号若有,都可以省略
public static void test6(){
Comparator<Integer> com2 = (o1,o2) -> {
return o1.compareTo(o2);
};
System.out.println(com2.compare(11,12));
System.out.println("**************");
Comparator<Integer> com3 = (o1,o2) -> o1.compareTo(o2);
System.out.println(com3.compare(11,12));
}
同样的,第四种可以省略大括号{}
public static void test7(){
Consumer<String> con4 = s -> {
System.out.println(s);
};
con4.accept("一个是听的人当真了,一个是说的人当真了");
System.out.println("**************");
Consumer<String> con5 = s -> System.out.println(s);
con5.accept("一个是听的人当真了,一个是说的人当真了");
}
4. Java内置的4大核心函数式接口
- Consummer 消费行接口,用途:对类型为T的对象应用操做,包含方法:void accept(T t)
void accept(T t) - Supplier 供给型接口,用途:返回类型为T的对象,包含方法:T get()
T get() - Function 函数式接口 用途:对类型为T的对象应用操作,并返回结果。结果是R
R apply(T t) 类型的对象。包含方法:R apply(T t) - Predicate 断定型接口 用途:确定类型为T的对象是否满足某约束,并返回boolean值。包含方法
boolean test(T t) boolean test
4.1 Consummer 消费行接口
public static void test1 (){
happyTime(500, new Consumer<Double>() {
@Override
public void accept(Double aDouble) {
System.out.println("学习太累了,去天上人间消费:" + aDouble);
}
});
System.out.println("************************");
happyTime(400,money -> System.out.println("消费:" + money));
}
public static void happyTime(double money, Consumer<Double> con){
con.accept(money);
}
4.2 Predicate 断定型接口
public static void test2(){
List<String> list = Arrays.asList("北京","南京","天津","普京");
ArrayList<String> filterStrs = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("京");
}
});
System.out.println(filterStrs);
System.out.println("****************************");
ArrayList<String> filterStrs1 = filterString(list,s -> s.contains("京"));
System.out.println(filterStrs1);
}
public static ArrayList<String> filterString (List<String> list, Predicate<String> pre){
ArrayList<String> filterList = new ArrayList<>();
for (String str:list){
if (pre.test(str)){
filterList.add(str);
}
}
return filterList;
}
5. 方法引用的使用
- 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。
- 方法引用:本质上就是Lambda表达式,而Lambda表达式作为函数式接口的实例。所以方法引用,也是函数式接口的实例。
- 使用格式:类(或者对象)::方法名
- 具体非为如下的三种情况:
1.对象::非静态方法 2.类::静态方法 3.类::非静态方法 - 方法引用的使用要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的形参列表和返回值类型相同。针对1和2
5.1 情况一:对象::实例方法
public static void test1 (){
Consumer<String> con1 = str -> System.out.println(str);
con1.accept("北京");
System.out.println("******************************");
PrintStream ps = System.out;
Consumer<String> con2 = ps::println;
con2.accept("上海");
}
public static void test2(){
Employee emp = new Employee(1000,"longxi",23,1000);
Supplier<String> sup1 = () -> emp.getName();
System.out.println(sup1.get());
System.out.println("******************************");
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
5.2 情况二:类::静态方法
public static void test3(){
Comparator<Integer> com1 = (t1,t2) ->Integer.compare(t1,t2);
System.out.println(com1.compare(11,21));
System.out.println("******************************");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(9,12));
}
public static void test4(){
Function<Double, Long> func1 = new Function<Double, Long>() {
@Override
public Long apply(Double aDouble) {
return Math.round(aDouble);
}
};
System.out.println("******************************");
Function<Double, Long> func2 = d -> Math.round(d);
System.out.println(func2.apply(12.3));
Function<Double, Long> func3 = Math::round;
System.out.println(func3.apply(13.6));
}
5.3 情况三:类::实例方法(有难度)
public static void test5(){
Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
System.out.println(com1.compare("abc","abd"));
System.out.println("******************************");
Comparator<String> com2 = String :: compareTo;
System.out.println(com2.compare("abda","fdasfe"));
}
public static void test6(){
BiPredicate<String,String> pre1 = (s1, s2)->s1.equals(s2);
System.out.println(pre1.test("fasfe","fegege"));
System.out.println("******************************");
BiPredicate<String,String> pre2 = String ::equals;
System.out.println(pre2.test("abc","abd"));
}
public static void test7(){
System.out.println("************test7******************");
Employee emp = new Employee(1000,"longxi",23,1000);
Function<Employee,String> func1 = e -> e.getName();
System.out.println(func1.apply(emp));
System.out.println("******************************");
Function<Employee,String> func2 = Employee :: getName;
System.out.println(func2.apply(emp));
}
6. 构造器引用
- 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
- 抽象方法的返回值类型即为构造器所属的类的类型
构造方法
public Employee (){
System.out.println("Employee()-------");
}
public static void test1 (){
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
System.out.println(sup.get());
System.out.println("******************************");
Supplier<Employee> sup1 = () -> new Employee();
System.out.println(sup1.get());
System.out.println("******************************");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
public static void test2(){
Function<Integer,Employee> func1 = id -> new Employee(id);
Employee apply = func1.apply(1000);
System.out.println(apply);
System.out.println("******************************");
Function<Integer,Employee> func2 = Employee::new;
Employee apply1 = func2.apply(1002);
System.out.println(apply1);
}
public static void test3(){
BiFunction<Integer,String,Employee > func1 = (id,name) ->new Employee(id,name);
System.out.println(func1.apply(1002,"longxi2"));
System.out.println("******************************");
BiFunction<Integer,String, Employee> func2 = Employee::new;
System.out.println(func2.apply(1002,"longxi3"));
}
7. 数组引用
可以把数组看成是一个特殊的类,则写法和构造引用一致。
public static void test4(){
Function<Integer, String[]> func1 = Length -> new String[Length];
System.out.println(Arrays.toString(func1.apply(5)));
System.out.println("******************************");
Function<Integer,String[]> func2 = String[]::new;
System.out.println(Arrays.toString(func2.apply(10)));
}
8. Stream API
Stream API提供了一种高效且易于使用的处理数据方式。 类似于使用SQL执行数据库查询。
8.1 为什么要使用Stream API
- 实际开发中,项目中多数数据源都来自于Mysql,Oracle等。但现在数据源可以更多了,有MongDB,Redis等,而这些NoSql的数据就需要Java层面去做处理。
- Stream 和Collection集合的区别:Collection是一种静态的内存数据结构,而Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
8.2 什么是Stream
Stream 是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列。 集合讲的数据,Stream讲的是计算
注意:
- Stream 自己不会存储元素。
- Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream
- Stream操作时延迟执行。这意味这他们会等到需要结果的时候才执行。
8.3 Stream操作的三个步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流 - 中间操作
一个中间操作链,对数据源进行处理 - 终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
8.4 Stream的创建方式
8.4.1 创建Stream方式一:通过结合
public static void test1(){
List<Employee> employees = EmployeeData.getEmployees();
Stream<Employee> stream = employees.stream();
Stream<Employee> employeeStream = employees.parallelStream();
}
8.4.2 创建Stream方式二:通过数组
public static void test2(){
int [] arr = new int[]{1,2,3,4};
IntStream stream = Arrays.stream(arr);
Employee employee = new Employee(1002, "longx");
Employee employee2 = new Employee(1002, "longx2");
Employee[] arr1 = new Employee[]{employee,employee2};
Stream<Employee> stream1 = Arrays.stream(arr1);
}
8.4.3 创建Stream方式三:Stream.of
public static void test3(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
}
8.4.4 创建Stream方式四:创建无限流
public static void test4(){
Stream.iterate(0,t -> t+2).limit(10).forEach(System.out::println);
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
8.5 Stream 的中间操作
8.5.1 筛选与切片
public static void test1(){
List<Employee> list = EmployeeData.getEmployees();
list.stream().filter(e ->e.getSalary() >7000).forEach(System.out::println);
System.out.println();
list.stream().limit(3).forEach(System.out::println);
System.out.println();
list.stream().skip(3).forEach(System.out::println);
System.out.println();
list.add(new Employee(1010,"刘强东",40, 8000));
list.add(new Employee(1010,"刘强东",40, 8000));
list.add(new Employee(1010,"刘强东",40, 8000));
list.add(new Employee(1010,"刘强东",40, 8000));
System.out.println(list);
list.stream().distinct().forEach(System.out::println);
}
8.5.2 映射
public static void test2(){
List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
List<Employee> employees = EmployeeData.getEmployees();
Stream<String> nameStream = employees.stream().map(e -> e.getName());
nameStream.filter(name -> name.length() > 3).forEach(System.out::println);
Stream<Stream<Character>> streamStream = list.stream().map(StreamTest1::fromStringToStream);
streamStream.forEach(s ->{
s.forEach(System.out::println);
});
System.out.println("flatMap");
Stream<Character> characterStream = list.stream().flatMap(StreamTest1::fromStringToStream);
characterStream.forEach(System.out::println);
}
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for (Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
8.5.3 排序
public static void test4(){
List<Integer> list = Arrays.asList(12, 45, 78, 32, -78, 797);
list.stream().sorted().forEach(System.out::println);
List<Employee> employees = EmployeeData.getEmployees();
employees.stream().sorted((e1,e2)->Integer.compare(e1.getAge(),e2.getAge())).forEach(System.out::println);
employees.stream().sorted((e1,e2)->{
int value = Integer.compare(e1.getAge(),e2.getAge());
if (value!= 0){
return value;
} else {
return Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
}
8.6 终止操作
8.6.1 匹配与查找
public class StreamTest2 {
public static void main(String[] args) {
test1();
test2();
}
public static void test1(){
List<Employee> list = EmployeeData.getEmployees();
boolean allMatch = list.stream().allMatch(e -> e.getAge() > 18);
System.out.println(allMatch);
boolean anyMatch = list.stream().anyMatch(e -> e.getSalary() > 10000);
System.out.println(anyMatch);
boolean noneMatch = list.stream().noneMatch(employee -> employee.getName().startsWith("雷"));
System.out.println(noneMatch);
Optional<Employee> first = list.stream().findFirst();
System.out.println(first);
Optional<Employee> any = list.stream().parallel().findAny();
System.out.println(any);
}
public static void test2 (){
List<Employee> list = EmployeeData.getEmployees();
long count = list.stream().filter(employee -> employee.getSalary() > 5000).count();
System.out.println(count);
Optional<Double> max = list.stream().map(e -> e.getSalary()).max(Double::compare);
System.out.println(max);
Optional<Employee> min = list.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min);
list.stream().forEach(System.out::println);
list.forEach(System.out::println);
}
}
8.6.2 规约
public static void test3(){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
System.out.println(list.stream().reduce(0,Integer::sum));
List<Employee> list1 = EmployeeData.getEmployees();
Stream<Double> rStream = list1.stream().map(Employee::getSalary);
Optional<Double> reduce = rStream.reduce(Double::sum);
System.out.println(reduce);
}
8.6.3 收集
List<Employee> list = EmployeeData.getEmployees();
List<Employee> employeeList = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
System.out.println();
Set<Employee> set = list.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
set.forEach(System.out::println);
9. Optional类
boy类
public class Boy {
private Girl girl;
@Override
public String toString() {
return "Boy{" +
"girl=" + girl +
'}';
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
public Boy(Girl girl) {
this.girl = girl;
}
}
girl类
public class Girl {
private String name;
public Girl() {
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Girl(String name) {
this.name = name;
}
}
测试类
private static void test1 (){
Girl girl = new Girl();
Optional.of(girl);
girl = null;
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);
Girl longxi = optionalGirl.orElse(new Girl("longxi"));
System.out.println(longxi);
}
测试结果
public static String getGirlName(Boy boy){
return boy.getGirl().getName();
}
public static String getGirlName1(Boy boy){
if (boy != null){
Girl girl = boy.getGirl();
if (girl!= null){
return girl.getName();
}
}
return null;
}
public static String getGirlName2(Boy boy){
Optional<Boy> boy1 = Optional.ofNullable(boy);
Boy boy2 = boy1.orElse(new Boy(new Girl("longxi1")));
Girl girl = boy2.getGirl();
Optional<Girl> girl1 = Optional.ofNullable(girl);
Girl longxi2 = girl1.orElse(new Girl("longxi2"));
return longxi2.getName();
}
private static void test3(){
Boy boy = new Boy();
String girlName = getGirlName1(boy);
boy = null;
String girlName2 = getGirlName2(boy);
System.out.println(girlName2);
boy = new Boy();
girlName2 = getGirlName2(boy);
System.out.println(girlName2);
boy = new Boy(new Girl("longxi3"));
girlName2 = getGirlName2(boy);
System.out.println(girlName2);
}
输出结果
|