JAVA8

Posted on By xqw

接口default默认实现

java历史原因,若想再现有的接口上添加一些方法,那么必须所有实现类都要实现才能通过编译。
如果用户自己实现了jdk原有,如List接口,那么更新版本后加一个stream方法,用户也必须实现,为解决不兼容,添加了default关键字

类似实现了多继承,继承多个default方法相同
菱形继承问题

  1. 类中的方法优先级最高。类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
  2. 如果无法依据第一条进行判断,那么子接口的优先级更高:函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体。
  3. 最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法,显式地选择使用哪一个默认方法的实现
     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>

方法引用

方法引用主要有三类。

  1. 指向静态方法的方法引用(例如Integer的parseInt方法, 写作Integer::parseInt)。
  2. 指向任意类型实例方法的方法引用(例如String的length方法,写作String::length)。
  3. 指向现有对象的实例方法的方法引用(假设你有一个局部变量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 long    
limit 中间(有状态有界) Stream long    
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