-
Notifications
You must be signed in to change notification settings - Fork 0
Java 8 特性
yangyp8110 edited this page Jan 17, 2018
·
1 revision
先看一个匿名类的实现:
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("runnable implements");
}
};
r1.run();
Lambda表达式实现:(r2必须要有和接受lambda兼容的接口类型)
//Runnable 有不接受参数并且无返回值的run接口与lambda兼容
Runnable r2 = () -> System.out.println("test lambda");
r2.run();
public interface NoArgsNoReturn{
void tt();
}
public interface OneArgsNoReturn{
void tt(String str);
}
public interface TwoArgsWithReturn {
String tt(String str1, String str2);
}
- 无参数
NoArgsNoReturn t1 = () -> System.out.println("test lambda");
t1.tt();
- 一个参数 && 无返回值
//一个参数无返回值,一个参数可以省略括号
OneArgsNoReturn t2 = str -> System.out.println(str);
t2.tt("test one args no return");
- 多个参数 && 有返回值
//两个参数并且有返回值
TwoArgsWithReturn t3 = (str1, str2) -> {
System.out.println("str1=" + str1 + ",str2=" + str2);
return str1 + " " + str2;
};
//TwoArgsWithReturn t3 = (str1, str2) -> str1 + " " + str2;
String ret = t3.tt("hello", "lambda");
@FunctionalInterface 会检测一个接口是否是函数式接口(是否只包含一个抽象方法),不是定义函数式接口
@FunctionalInterface//会检测一个接口是否是函数式接口(是否只包含一个抽象方法)
public interface MyFunc<T> {
T getValue(T t);
}
@FunctionalInterface//检测一个接口是否是函数式接口
public interface MyFunc<T> {
T getValue(T t);
}
public String toUpperString(MyFunc<String> func,String str){
return func.getValue(str);
}
lambda作为参数传递:
String ret = toUpperString(str -> str.toUpperCase(), "abcdefg");
System.out.println(ret);
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer消费型接口 | T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get(); |
Function<T, R>函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t); |
Predicate断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean 值。包含方法boolean test(T t); |
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T, U, R> | T, U | R | 对类型为 T, U 参数应用操作,返回 R 类型的结果。包含方法为R apply(T t, U u); |
UnaryOperator (Function 子接口) ) | T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(T t); |
BinaryOperator( (n BiFunction 子接口) ) | T, T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1, T t2); |
BiConsumer<T, , U> | T, U | void | 对类型为T, U 参数应用操作。包含方法为void accept(T t, U u) |
ToIntFunction、ToLongFunction、ToDoubleFunction | T | int、long、double | 分 别 计 算 int 、 long 、double、值的函数 |
IntFunction、LongFunction、DoubleFunction | int、long、double | R | 参数分别为int、long、double 类型的函数 |
- 当要传递给Lambda体的操作,已经有实现的方法了,就可以使用方法引用
- 方法引用:使用操作符 “ ::” 将方法名和对象或类的名字分隔开来。
- 如下三种主要使用情况 :
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
/** 必须要有相同的参数与返回值*/
(x) -> System.out.println(x);
//等同于:
System.out::println
/** R apply(T t, U u); */
BinaryOperator<Double> b = (x, y) -> Math.pow(x, y);
b.apply(2.0, 1.0);
//等同于:
BinaryOperator<Double> b1 = Math::pow;
b1.apply(1.0, 2.0);
//数组引用
Function<Integer, Integer[]> func = n -> new Integer[n];
//等同于:
Function<Integer, Integer[]> func2 = Integer[]::new;
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
- Stream是什么
- 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
- 注意:
- Stream 自己不会存储元素。
- Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
- Stream操作的三个步骤
- 创建stream -- 一个数据源(如: 集合、数组), 获取一个流
- 中间操作 -- 一个中间操作链,对数据源的数据进行处理
- 终止操作 -- 一个终止操作,执行中间操作链,并产生结果
- 筛选与切片
方 法 | 描 述 |
---|---|
filter(Predicate p) | 接收 Lambda , 从流中排除某些元素。 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
- 映射
方 法 | 描 述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
- 排序
方 法 | 描 述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
-
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer,甚至是 void 。
-
查找与匹配
方 法 | 描 述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如: List、 Integer,甚至是 void 。 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反, Stream API 使用内部迭代——它帮你把迭代做了) |
- 归约
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
方 法 | 描 述 |
---|---|
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回 Optional |
- 收集
方 法 | 描 述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、 Set、 Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例, 具体方法与实例如下表:(使用示例:Demo)
方法 | 返回类型 | 作用 |
---|---|---|
toList | List | 把流中元素收集到List |
toSet | Set | 把流中元素收集到Set |
toCollection | Collection | 把流中元素收集到创建的集合 |
counting | Long | 计算流中元素的个数 |
summingInt | Integer | 对流中元素的整数属性求和 |
averagingInt | Double | 计算流中元素Integer属性的平均值 |
summarizingInt | IntSummaryStatistics | 收集流中Integer属性的统计值。(count,sum,max,min,avg) |
joining | String | 连接流中每个字符串 |
maxBy | Optional | 根据比较器选择最大值 |
minBy | Optional | 根据比较器选择最小值 |
reducing | 归约产生的类型 | 从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值 |
collectingAndThen | 转换函数返回的类型 | 包裹另一个收集器,对其结果转换函数 |
groupingBy | Map<K, List> | 根据某属性值对流分组,属性为K,结果为V |
partitioningBy | Map<Boolean, List> | 根据true或false进行分区 |
Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰。
public interface MyFunc{
String Func(String a);
//默认方法
default String getName(){
return "interface default method";
}
}
public interface MyFunc{
String Func(String a);
default String getName(){
return "interface default method";
}
//静态方法
static String getDesc(){
return "static method";
}
}
- 当一个类继承多个接口,接口含有同名默认方法时,类调用方法要加上接口前缀
@Override
public String getName() {
return MyFunc.super.getName();
}
Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
- 常用方法:
方法 | 说明 |
---|---|
Optional.of(T t) | 创建一个 Optional 实例 |
Optional.empty() | 创建一个空的 Optional 实例 |
Optional.ofNullable(T t) | 若 t 不为 null,创建 Optional 实例,否则创建空实例 |
isPresent() | 判断是否包含值 |
orElse(T t) | 如果调用对象包含值,返回该值,否则返回t |
orElseGet(Supplier s) | 如果调用对象包含值,返回该值,否则返回 s 获取的值 |
map(Function f) | 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty() |
flatMap(Function mapper) | 与 map 类似,要求返回值必须是Optional |