jdk8 新特性

函数式接口:

函数式接口是什么?如果接口中只声明有一个抽象方法,则此接口成为函数式接口(FunctionalInterface)

为什么要有函数式接口?因为只有给函数式接口创建对象时,才可以使用lambda表达式。

java8中声明的函数式接口所在包:java.util.function

4个基本的函数式接口:(直接copy宋的课件)

函数式接口 称谓 参数类型 用途
Consumer<T> 消费型接口 T 对类型为T的对象应用操作,包含方法: void accept(T t)
Supplier<T> 供给型接口 返回类型为T的对象,包含方法:T get()
Function<T, R> 函数型接口 T 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t)
Predicate<T> 判断型接口 T 确定类型为T的对象是否满足某约束,并返回 boolean 值。包含方法:boolean test(T t)

lambda表达式

lambda表达式怎么用?

语法规则:

->的左边:lambda的形参列表,参数的类型都可以省略。如果形参列表只有一个,则一对()也可以省略。

->的右边:lambda体,只有一行执行语句时,则一对{}可以省略,如果有return,则也要省略。

写法举例

1
Comparator<Integer> com = (o1 , o2) -> Integer.compara(o1,o2);

lambda表达式的本质:

一方面,lambda表达式作为接口实现类的对象;另一方面,lambda表达式是匿名函数。

方法引用

  • 方法引用可以看作是lambda表达式的进一步刻画。

  • 当需要提供一个函数式接口的实例时,我们可以使用lambda表达式提供此实例。

    • 当满足一定的条件是,我们还可以使用方法引用或构造器引用替换lambda表达式。

方法引用作为了函数式接口的实例。

格式:

  1. 对象 :: 实例方法
    要求:函数式接口的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同。此时可以考虑使用方法b实现对a的替换、覆盖。
    注意此方法b是非静态方法,需要对象调用。
  2. 类 :: 静态方法
    要求:函数式接口的抽象方法a与其内部实现时调用的对象的某个静态方法b的形参列表和返回值类型都相同。此时可以考虑使用方法b实现对a的替换、覆盖。
    注意此方法b是静态方法,需要类调用。
  3. 类 :: 实例方法
    要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同。同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第一个参数作为方法b的调用者,且抽象方法a的后n-1个参数与方法b的n-1个参数的类型相同(或一致)。
    注意此方法b是非静态方法,需要对象调用。但是形式上,写出对象a所属的类。

构造器引用

格式:类名 :: new

调用了类名对应的类中某一个确定的构造器。具体调用的是类中的哪一个构造器,取决于函数式接口的抽象方法的形参列表。

数组引用

格式:数组名 :: new

StreamAPI

Stream使用的流程

  1. 实例化
  2. 一系列的中间操作
  3. 执行终止操作

实例化:

三种方法:

方法一:通过集合

例如:对于List结构,直接使用list.stream()就能创建stream实例

方法二:通过数组

类似方法一,使用Arrays的静态方法stream()Arrays.stream(arr)

方法三:streamof

public static<T> Stream<T> of(T... values) : 返回一个流

例如:

1
2
Stream<Integer> stream = Stream.of(1,2,3,4,5);
stream.forEach(System.out::println);

中间操作:

筛选与切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Test
public void test1() {
//创建Stream
List<Employee> list = EmployeeData.empData();
Stream<Employee> stream = list.stream();
//filter(Predicate p) 过滤
stream.filter(e -> e.getAge() > 20).forEach(System.out::println);
//limit(long maxSize) 限制元素个数
list.stream().limit(2).forEach(System.out::println);
//skip(long n) 跳过前n个元素
list.stream().skip(2).forEach(System.out::println);
//distinct() 去掉重复元素
list.add(new Employee(22,"Jack"));
list.stream().distinct().forEach(System.out::println);
}

映射

1
2
3
4
5
6
7
    @Test
public void test2(){
//map(Function f) 映射
List<String> list = Arrays.asList("aa","bb","cc","dd");
// list.stream().map(s -> s.toUpperCase()).forEach(System.out::print);
list.stream().map(String :: toUpperCase).forEach(System.out::print);
}

排序

1
2
3
4
5
6
7
8
9
@Test
public void test3(){
//sorted(Comparator c) 排序
Integer [] arr = {1,2,3,4,5,6};
Arrays.stream(arr).sorted((o1, o2) -> o2-o1).forEach(System.out::print);

List<Employee> list = EmployeeData.empData();
list.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).forEach(System.out::println);
}

终止操作:

匹配与查找

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test4(){
List<Employee> list = EmployeeData.empData();
//allMatch(Predicate p) 检查是否匹配所有元素
System.out.println(list.stream().allMatch(e -> e.getAge() > 20));
//anyMatch(Predicate p) 检查是否至少匹配一个元素
System.out.println(list.stream().anyMatch(e -> e.getAge() > 20));
//findFirst() 返回第一个元素
System.out.println(list.stream().findFirst());
//forEach(Consumer c) 迭代
list.stream().forEach(System.out::println);
}

归约

1
2
3
4
5
6
@Test
public void test6(){
List<Employee> list = EmployeeData.empData();
//reduce(T identity, BinaryOperator b) 归约
System.out.println(list.stream().map(Employee::getAge).reduce(0,Integer::sum));
}

收集

1
2
3
4
5
6
7
8
9
10
@Test
public void test7(){
List<Employee> list = EmployeeData.empData();
//collect(Collectors.toList()) 收集到List
List<Integer> list1 = list.stream().map(Employee::getAge).collect(Collectors.toList());
//collect(Collectors.toSet()) 收集到Set
Set<Integer> set = list.stream().map(Employee::getAge).collect(Collectors.toSet());
//collect(Collectors.toMap()) 收集到Map
Map<Integer, Integer> map = list.stream().map(Employee::getAge).collect(Collectors.toMap(e -> e, e -> e));
}

JavaSE学习先到这里,中间跳了集合源码、网络编程、反射的内容,之后的考试是真的有点多(光电你罪该万死,数电、单片机、量子力学、热统都让我一个学期考还一堆实验课Щ(◣д◢)Щ),后续打算边用边学,保持写代码的习惯。