接口default默认实现
java历史原因,若想再现有的接口上添加一些方法,那么必须所有实现类都要实现才能通过编译。
如果用户自己实现了jdk原有,如List接口,那么更新版本后加一个stream方法,用户也必须实现,为解决不兼容,添加了default关键字
类似实现了多继承,继承多个default方法相同
菱形继承问题
- 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
- 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
- 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现
public interface P{ default void hello() { System.out.println("P"); } } /*--------1----------*/ public interface A extends P{ } public interface B extends P{ } //编译通过 输出P public class C implements A, B{ } /*--------2----------*/ public interface A extends P{ default void hello() { System.out.println("A"); } } public interface B extends P{ default void hello() { System.out.println("B"); } // void hello(); } //必须要重新实现:两个default或者其中有一个不是default public static class C implements A, B{ @Override public void hello() { } }
函数式接口
只有一个抽象方法的接口,可以接收lambda表达式,允许default、static方法和Object的几个方法(equals)
public interface Predicate<T>{
boolean test (T t);
}
-
java8拥有默认方法(即在类没有对方法进行实现时,其主体为方法提供默认实现的方法)。哪怕有很多默认方法,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。
-
@FunctionalInterface 用@FunctionalInterface定义了一个接口,而它却不是函数式接口的话,编译器将返回一个提示原因的错误
jdk默认函数式接口
Predicate
public interface Predicate<T>{
boolean test (T t);
}
返回boolean,多用来判断
Consumer
public interface Consumer<T>{
void accept(T t);
}
返回空,用来对t做一些操作
Function
接收一个T返回一个R
public interface Function<T, R>{
R apply(T t);
}
例子
public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for (T s : list) {
result.add(f.apply(s));
}
return result;
}
// [7, 2, 6]
List<Integer> l = map(
Arrays.asList("lambdas", "in", "action"),
(String s) -> s.length()
);
其他
Java 8中的常用函数式接口
| 函数式接口 | 函数描述符 | 原始类型特化 |
|---|---|---|
| Predicate |
T->boolean | IntPredicate,LongPredicate, DoublePredicate |
| Consumer |
T->void | IntConsumer,LongConsumer, DoubleConsumer |
| Function<T,R> | T->R | IntFunction |
| IntToDoubleFunction, | ||
| IntToLongFunction, | ||
| LongFunction |
||
| LongToDoubleFunction, | ||
| LongToIntFunction, | ||
| DoubleFunction |
||
| ToIntFunction |
||
| ToDoubleFunction |
||
| ToLongFunction |
||
| Supplier |
()->T | BooleanSupplier,IntSupplier, LongSupplier,DoubleSupplier |
| UnaryOperator |
T->T | IntUnaryOperator,LongUnaryOperator,DoubleUnaryOperator |
| BinaryOperator |
(T,T)->T | IntBinaryOperator,LongBinaryOperator,DoubleBinaryOperator |
| BiPredicate<L,R> | (L,R)->boolean | |
| BiConsumer<T,U> | (T,U)->void | ObjIntConsumer |
| ObjLongConsumer |
||
| ObjDoubleConsumer |
||
| BiFunction<T,U,R> | (T,U)->R | ToIntBiFunction<T,U>, |
| ToLongBiFunction<T,U>, | ||
| ToDoubleBiFunction<T,U> |
方法引用
方法引用主要有三类。
- 指向静态方法的方法引用(例如Integer的parseInt方法, 写作Integer::parseInt)。
- 指向任意类型实例方法的方法引用(例如String的length方法,写作String::length)。
- 指向现有对象的实例方法的方法引用(假设你有一个局部变量expensiveTransaction 用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensiveTransaction::getValue)。
public class Apple{
public Apple(Integer weight){
}
/*------一个参数-------*/
//等价:c2 = (weight) -> new Apple(weight);
Function<Integer, Apple> c2 = Apple::new;
Apple a2 = c2.apply(110);
/*------构建列表-------*/
List<Integer> weights = Arrays.asList(7, 3, 4, 10);
List<Apple> apples = map(weights, Apple::new);
public static List<Apple> map(List<Integer> list, Function<Integer, Apple> f){
List<Apple> result = new ArrayList<>();
for(Integer e: list){
result.add(f.apply(e));
}
return result;
}
/*------将构造器缓存,类似工厂模式-------*/
static Map<String, Function<Integer, Fruit>> map = new HashMap<>(){
{
map.put("apple", Apple::new);
map.put("orange", Orange::new);
}
};
Apple a = map.get("apple").apply(weight);
}
Stream流
常用中间操作和终端操作
| 操 作 | 类 型 | 返回类型 | 使用的类型/函数式接口 | 函数描述符 |
|---|---|---|---|---|
| filter | 中间 | Stream |
Predicate |
T -> boolean |
| distinct | 中间(有状态无界) | Stream |
||
| skip | 中间(有状态有界) | Stream |
||
| limit | 中间(有状态有界) | Stream |
||
| map | 中间 | Stream |
Function<T, R> | T -> R |
| flatMap | 中间 | Stream |
Function<T, Stream |
T -> Stream |
| sorted | 中间(有状态无界) | Stream |
Comparator |
(T, T) -> int |
| anyMatch | 终端 | boolean | Predicate |
T -> boolean |
| noneMatch | 终端 | boolean | Predicate |
T -> boolean |
| allMatch | 终端 | boolean | Predicate |
T -> boolean |
| findAny | 终端 | Optional |
||
| findFirst | 终端 | Optional |
||
| forEach | 终端 | void | Consumer |
T -> void |
| collect | 终端 | R | Collector<T, A, R> | |
| reduce | 终端(有状态有界) | Optional |
BinaryOperator |
(T, T) -> T |
| count | 终端 | long |
静态导入收集器的所有成员是一种惯例和明智的做法,因为它使流管道更易于阅读
分组,统计,求和
public class Test {
public static void main(String[] args) {
List<OrdersDO> list = new ArrayList<>();//查询昨天一天的所有交易
OrdersDO o1 = new OrdersDO();
o1.setAppId(1L);
o1.setTradeAmount(100L);
o1.setStatus(1);
list.add(o1);
OrdersDO o2 = new OrdersDO();
o2.setAppId(5L);
o2.setTradeAmount(300L);
o2.setStatus(2);
list.add(o2);
OrdersDO o3 = new OrdersDO();
o3.setAppId(1L);
o3.setTradeAmount(100L);
o3.setStatus(3);
list.add(o3);
OrdersDO o4 = new OrdersDO();
o4.setAppId(5L);
o4.setTradeAmount(300L);
o4.setStatus(4);
list.add(o4);
OrdersDO o5 = new OrdersDO();
o5.setAppId(5L);
o5.setTradeAmount(300L);
o5.setStatus(4);
list.add(o5);
//统计每个应用实际支付总额
Map<Long, Long> tradeAmountMap = list.stream().filter(o->o.getStatus()==2)
.collect(Collectors.groupingBy(OrdersDO::getAppId,
Collectors.summingLong(OrdersDO::getTradeAmount)));
System.out.println(tradeAmountMap);
//统计每个应用取消总额
Map<Long, Long> cancelAmountMap = list.stream()
.collect(Collectors.groupingBy(OrdersDO::getAppId,
Collectors.summingLong(OrdersDO::getTradeAmount)));
System.out.println(cancelAmountMap);
//统计每个应用下交易笔数
Map<Long, Long> appTradeNum = list.stream().collect(Collectors.groupingBy(OrdersDO::getAppId, Collectors.counting()));
System.out.println(appTradeNum);
//统计每个应用每种状态下交易笔数
Map<Long, Map<Integer, Long>> tradeNumMap = list.stream().
collect(Collectors.groupingBy(OrdersDO::getAppId,
Collectors.groupingBy(OrdersDO::getStatus,
Collectors.counting()))); //Collectors.summarizingInt()求和等
System.out.println(tradeNumMap);
//每个应用下交易笔数按数量排序
Map<Long,Long> finalMap = new LinkedHashMap<>();
appTradeNum.entrySet().stream().sorted(Map.Entry.<Long, Long>comparingByValue().reversed()).forEachOrdered(e->finalMap.put(e.getKey(),e.getValue()));
System.out.println(finalMap);
}
}
Optional使用场景
http://weishu.me/2015/12/08/use-optional-avoid-nullpointexception/
新的 date API
常用类:
- LocalDateTime LocalDate和LocalTime 从人的时间思维设计
- Instant 机械处理 更精确
- Duration Period 处理两个时间 Duration(两个time) Period(两个date)
- TemporalAdjuster 函数接口 TemporalAdjusters静态工厂 对日期进行特殊化操作(lastDayOfMonth…)
- 格式化 DateTimeFormatter