一,lammda表达式的使用
函数式接口:就是一个接口中只有一个抽象方法,lammda表达式其实就是创建一个接口实例,并对这个抽象方法进行重写
java8内置四大核心函数式接口
java.util.function包下的接口都是“无意义”的,这个“无意义”并不是说它们没有存在的意义,而是说它们都必须放到具体的语境中去才会真正的意义。或者说,它们是“非典型”的Java API就体现在,它们自己是没有语境(Context)的,它们实际上可以说就是为Lambda表达式而存在的——你不需要了解它叫什么(匿名的),它们是作为参数在对象的方法的中传递的。
其实,所有java.util.function包下的接口的方法名,我们都不必关心,因为当我们用它们的时候,压根不会去显式地调用它们,方法名也是“无意义”的,它们只是方便大家去理解他的用途。但是,方法的参数和返回值是需要我们关心和注意的。
function包下总共有43个接口,可分为这四类核心函数式接口:Function、Supplier、Consumer、Predicate。
1.消费型接口
Consumer:消费型接口 单一抽象方法为:void accept(T t);
-
作用:消费某个对象**(传入一个泛型参数,不返回任何值)**
-
举例:forEach: Iterable接口的foeEach方法 需要传入Consumer,大部分集合类都实现了该接口,用于返回Iterator对象进行迭代。
2.供给型接口
Supplier:供给型接口 T get();
- 作用:创建一个对象(工厂类)(不传入参数,返回一个值)
- 举例:Optional.orElseGet(Supplier<? extends T>):当this对象为null,就通过传入supplier创建一个T返回。(Optional类是一种容器对象,要么包装值,要么为空)
3.函数式接口
Function<T,R>:函数型接口 R apply(T t);
- 作用:实现一个“一元函数”,即传入一个值经过函数的计算返回另一个值。(传入一个参数,返回一个值)
4.断言型接口
Predicate:断言型接口 单一抽象方法: boolean test(T t);
作用:判断对象是否符合某个条件**(传入一个参数,返回一个布尔值)**
举例:主要用于流的筛选。给定一个包含若干项的流,Stream接口的filter方法传入一个Predicate并返回一个新的流,它仅包含满足给定谓词的项。
方法引用:
方法引用就是lammda表达式的简化版,就是说函数式接口中抽象方法已经有类去实现了,咱们就可以直接调用这个方法
主要有三种表现形式:
1)引用特定对象的实例方法:对象::实例方法名(object::instanceMethod)
(x)->System.out.println(x);
简化为:System.out::println
2)引用静态方法:类::静态方法名(Class::staticMethod)
()->Math.random();
简化为:Math::random
3)调用特定类型的任意对象的实例方法: 类::实例方法名(Class::instanceMethod ):这个比较特殊,可能接口中的抽象方法和引用方法格式不同,而是接口中的抽象方法如果可以调用这个方法,那么就可以通过这个方法的类名加实例方法去调用引用方法
x->x.length();
简化为:String::length
注意:如果通过类名引用一个传入多个参数的方法,则上下文提供的第一个元素将作为方法的目标,其他元素作为方法的参数,可以使用ClassName::instanceMethod 。
(o1,o2)->o1.compareTo(o2);
简化为:String::compareTo
注意:需要实现的接口中的抽象方法的 参数列表与返回值类型 要与 当前调用的方法的参数列表、返回值类型保持一致
StreamApi的使用:检索集合或者数组
特点:1.与集合不同,集合是与内存打交道,而Stream Api是与cpu打交道
2.延迟执行,只有在需要结果的时候才会执行,或者执行了终止操作的时候才会执行
大概步骤就是:
1.获取stream实例对象
通过集合获取stream对象:集合实例.stream();
通过数组获取stream对象:Arrays.stream(数组实例)
通过Stream类下自带的of方法,of的参数就是任意元素
2.中间操作
(1)筛选与切片
filter(predicate p):对元素进行筛选
limit(n) :获取前n条数据
skip(n) : 跳过前n条数据,返回后边的数据
distinct():元素去重
(2)映射
map(Function f):对元素进行修改或者操作,返回一个新的stream实例
flatMap(Function f):与map的区别就是,在操作中返回的新的stream实例,里边的元素应该还是stream实例,如果是map的话就会stream里边嵌套stream,如果这flatmap,就会把里边的stream拆解,追加到外边的stream中
(3)排序
Sorted():可以是自然排序,如果元组本身就可以直接排序就可以使用自然排序
Sorted(Comparator<T> c):可以自己进行定制,如果是对象,要根据某个元素排序就需要用到定制排序,一下就是根据对象年龄参数进行升序排序
3.终止操作
allMatch(predicate p):检查是否匹配所有元素
anyMatch(predicate p)检查是否至少匹配一个元素
noneMatch(predicate p)检查是否没有匹配的元素
findFirst()返回第一个元素
findany()返回任意元素
count()返回元素总个数
max(Comparator c)返回流中最大值
min(Comparator c)返回流中最小值
forEach(Consumer c) 内部迭代
归约结束操作:
reduce(T 起始值,BinaryOperator),这里可以设置起始值,将流中的元素反复结合起来
eg:list.stream().reduce(0,Integer::Sum)
reduce(BinaryOperator) 不设置起始值,求元素的和
收集结束操作:
collect(Collector c)
eg:list.stream().collect(Collector.Toset)
list变换map的常用操作:
//以brand和price属性分别作为key和value创建map,若集合中存在key重复的元素,就取后一个
Map<String, BigDecimal> collect = cars.stream().collect(Collectors.toMap(Car::getBrand, Car::getPrice, (x, y) -> y));
//以brand为key,将集合分组,每个brand对应一个Car集合
Map<String, List<Car>> collect1 = cars.stream().collect(Collectors.groupingBy(Car::getBrand));
//将集合按是否满足partitioningBy中的断言函数为标准,分成两个集合
Map<Boolean, List<Car>> bn = cars.stream().collect(Collectors.partitioningBy(k -> "BMW".equals(k.getBrand())));
三,Optional类的使用
可以防止空指针的发生
获取optional类实例的三种方式:
Optional.of(T f):创建一个Optional实例,t必须为空
Optional.empty():创建一个空的Optional实例
Optional.ofNullable(T t):t可以为null
optional类实例方法的使用:
orElse(T t):调用者如果为空就使用参数中的实例
eg:Optional<Boy> o=Optional.ofNullable(new Boy());
Boy b= o.orElse(new BOY);//假如o为null,就使用后边的对象为boy赋值