java8新特性学习笔记

1. HashMap 在数组-链表的基础上加上了红黑数(在碰撞的个数大于8时,并且总容量大于64时)将链表转为红黑树;ConcurrentHashMap采用了CAS算法。

2. 1.8后内存结构发生改变,原来的方法区——堆中的永久区(PremGen)将被从堆中分离,取而代之的为元空间(MetaSpace),与之前的不同的是它直接使用物理内存,PremGenSize和MaxPremGenSize这两个调优参数将无效,取而代之的是MetaSpaceSize和MaxMetaSpaceSize

3.1 Lamdba是一个匿名函数,Llamdba表达式可以被理解为一段可传递的代码(将代码想数据一样传递);Lambda表达式需要“函数式接口”(接口中只有一个抽象方法的接口)的支持,用@FunctionalInterface修饰,可检测是否为函数式接口;

/*Lambda表达式基础语法:"->"该操作符将Lambda表达式分为两部分
 *左侧:Lambda表达式的参数列表
 *右侧:Lambda表达式中所需执行的功能,即Lambda体
 *
 *语法格式一:无参数无返回值
 *    接口 对象 =()-> Lambda体
 *
 *语法格式二:有一个参数无返回值  
 *    接口 对象 =(参数)-> Lambda体
 *
 *语法格式三:有一个参数小括号可以不写 
 *    接口 对象 = 参数 -> Lambda体
 *
 *语法格式四:有两条以上参数,有返回值,并且Lambda体中有多条语句  
 *    接口 对象 = (参数,参数)->{
 *        Lambda体
 *        return 返回值;
 *    };
 *
 *语法格式五:有两条以上参数,有返回值,并且Lambda体中只有一条语句
 *    接口 对象 = (参数,参数)->Lambda体
 *  
 *语法格式六:Lambda表达式的参数列表的数据类型可以不写,因为可以根据上下文进行类型推断
 */
   

3.2 java8提供的四大内置核心函数式接口与其子接口

/**
 * 四大核心接口
 * Consumer<T> : 消费型接口
 *      void accept(T t);
 * Supplier<T> : 供给型接口
 *      T get();
 * Function<T,R> : 函数型接口
 *      R apply(T t);
 * Predicate<T> : 断言型接口
 *      boolean test(T t);
 */

public class test{
    @Test
    public void test1() {
        happy(1000,(money)-> System.out.println("特殊消费:"+money+"元"));
    }

    public void happy(double money, Consumer<Double> con){
        con.accept(money);
    }

    @Test
    public void test2(){
         List<Integer> list = getNumList(10,()->(int)(Math.random() * 100));
         for(Integer num : list){
             System.out.println(num);
         }
    }

    public List<Integer> getNumList(int num, Supplier<Integer> sup){
        List<Integer> list = new ArrayList<>();
        for(int i =0;i<num;i++){
            Integer n = sup.get();
            list.add(n);
        }
        return list;
    }

    @Test
    public void test3(){
        String s = strHandler("\t\t\t 看我前面有东西吗?",(str)->str.trim());
        System.out.println(s);
    }

    public String strHandler(String str, Function<String,String> fun){
        return fun.apply(str);
    }

    @Test
    public void test4(){
        List<String> list = Arrays.asList("你好啊!","你是","看","不到","我的","你只能看到我!");
        List<String> s = filterStr(list,(st)->st.length() >3);
        for(String str : s){
            System.out.print(str);
        }
    }

    public List<String> filterStr(List<String> list, Predicate<String> pre){
        List<String> strList = new ArrayList<>();
        for(String str : list){
            if(pre.test(str)){
                strList.add(str);
            }
        }
        return strList;
    }
}

/**其他接口
 * BiFunction<T,U,R> 参数类型 T U  返回类型 R
 * UnaryOperator<T> 参数类型 T   返回类型 T
 * BinaryOperator<T> 参数类型 T T  返回类型 T
 * BiConsumer<T,U> 参数类型 T U  返回类型 void
 * ToIntFunction<T> 参数类型 T  返回类型 int
 * ToLongFunction<T> 参数类型 T  返回类型 long
 * ToDoubleFunction<T> 参数类型 T  返回类型 double
 * IntFunction<T> 参数类型 int  返回类型 R
 * LongFunction<T> 参数类型 long 返回类型 R
 * DoubleFunction<T> 参数类型 double  返回类型 R
 */

3.3 若Lamdba体中的内容有方法已经实现了我们就可以使用“方法引用”,语法格式:对象::实例方法名,类::静态方法名,类::实例方法名(第一个参数是方法的调用者,第二个参数是方法的参数时可用);构造器引用格式:ClassName::new; 数组引用:Type[]::new; 以上用法都应遵行Lamdba体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致。

4.1 流(Stream)是数据渠道,用与操作数据源(集合,数组等)所生成的元素序列(集合讲的是数据,流讲的是计算);Stream的操作步骤:创建Stream(一个数据源获取一个流)——>中间操作——>终止操作(产生一个新的流,数据源不变)

4.1.1创建Stream的方法

//1.可以通过Collection系列集合提供的stream()(此方法获取的是串型流)或parallelStream()(此方法获取的是并型流)
//示例
List<String> list = new ArrayList<>();
Stream<String> st1 = list.stream();

//2.通过Arrays中的静态方法stream()获取数据流
//示例
Employee[] emps = new Employee[10];
Stream<Employee> st2 = Arrays.Stream(emps);

//3.通过Stream类中的静态方法of()
//示例
Stream<String> st3 = Stream.of("aa","bb","cc");

//4.创建无限流
//示例
//迭代
Stream<Integer> st4 = Stream.iterate(0,(x)->x+2);
//生成
Stream.generate(()->Math.random())

4.1.2 Stream的中间操作

/**
 *筛选与切片操作
 *filter--接收Lamdba,从流中通过条件筛选
 *limit--截断流,使其元素不超过给定数量。
 *skip(n)--跳过元素,返回一个扔掉了前n个元素的流,若该流中元素不足 n个,则返回一个空流,与limit(n)互补
 *distinct--筛选,通过流所生成元素的hashCode()和equals()去除重复元素
 */

//将多个FlyPig对象装入List中,使用前提是有一个名为FlyPig的bean
    List<FlyPig> fp = Arrays.asList(
            new FlyPig("aaaa","AAAA","1111"),
            new FlyPig("bbbb","BBBB","2222"),
            new FlyPig("cccc","CCCC","3333"),
            new FlyPig("dddd","DDDD","4444"),
            new FlyPig("eeee","EEEE","5555"),
            new FlyPig("aaaa","AAAA","1111"),
            new FlyPig("aaaa","AAAA","1111")
    );

    @Test
    public void test1(){
        fp.stream()
                .filter((e)->e.getName().equals("aaaa"))//中间操作
                .forEach(System.out::println);//终止操作
    }

    @Test
    public void test2(){
        fp.stream()
                .limit(2)
                .forEach(System.out::println);//终止操作
    }

    @Test
    public void test3(){
        fp.stream()
                .skip(2)
                .forEach(System.out::println);//终止操作
    }

    @Test
    public void test4(){
        fp.stream()
                .distinct()//去重的要求是bean中有写hashCode()和equals()方法
                .forEach(System.out::println);//终止操作
    }

/**
     * 映射
     * map--接收Lamdba,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
     * flatMap--接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流链接成一个流
     */

    @Test
    public void test5(){
        List<String> list = Arrays.asList("aaa","bbb","ccc","ddd");
        list.stream()
                .map((str)->str.toUpperCase())
                .forEach(System.out::println);
        System.out.println("-------------------------------------------");
        fp.stream()
                .map(FlyPig::getName)
                .map((str)->str.toUpperCase())
                .forEach(System.out::println);
        System.out.println("-------------------------------------------");
//        Stream<Stream<Character>> stream= list.stream()
//                .map(streamTest::filterCharacter);//{{a,a,a},{b,b,b},{c,c,c},{d,d,d}}
//        stream.forEach((sm)->{
//            sm.forEach(System.out::println);
//        });
        System.out.println("-------------------------------------------");
        list.stream()
                .flatMap(streamTest::filterCharacter)//{a,a,a,b,b,b,c,c,c,d,d,d}
                .forEach(System.out::println);
    }

    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for(Character ch : str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

    /**
     * 排序
     * sorted()--自然排序
     * sorted(Comparator com)--定制排序
     */
    @Test
    public void test7(){
        List<String > list = Arrays.asList("cccc","aa","aaaa","bb","b");
        list.stream()
                .sorted()
                .forEach(System.out::println);

        System.out.println("-------------------------");
        fp.stream()
                .sorted((e1,e2)->{
                    if(e1.getCar().equals(e2.getCar())){
                        return e1.getName().compareTo(e2.getName());
                    }else{
                        return -e1.getCar().compareTo(e2.getCar());
                    }
                }).forEach(System.out::println);
    }

4.1.3 Stream的终止操作

/**
 * @author ZSP
 * @Project: javaTest
 * @Package:test
 * @date 2018/9/5 10:59
 * @Description: Stream的终止操作
 **/
public class streamTest2 {
    List<Employee> employees = Arrays.asList(
            new Employee("张三",14,3426.99, Employee.Status.FREE),
            new Employee("李四",15,3332.34, Employee.Status.BUSY),
            new Employee("王五",34,4322.23, Employee.Status.VOCATION),
            new Employee("赵六",23,2433.56, Employee.Status.FREE),
            new Employee("田七",25,2442.78, Employee.Status.BUSY)
    );

    /**
     * 查找与匹配
     * allMatch--检查是否匹配所有元素
     * anyMatch--检查是否至少匹配一个元素
     * noneMatc--检查是否是没有匹配所有元素
     * findFirst--返回第一个元素
     * findAny--返回当前流中的任意元素
     * count--返回流中元素的总个数
     * max--返回流中的最大值
     * min--返回流中的最小值
     */
    @Test
    public void test1(){
        boolean b1=employees.stream()
                .allMatch((e)->e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);

        System.out.println("---------------------------------");

        boolean b2=employees.stream()
                .anyMatch((e)->e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);

        System.out.println("---------------------------------");

        boolean b3=employees.stream()
                .noneMatch((e)->e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b3);

        System.out.println("---------------------------------");

        Optional<Employee> op1 =employees.stream()
                .sorted((e1,e2)->Double.compare(e1.getSlary(),e2.getSlary()))
                .findFirst();
        System.out.println(op1.get());

        System.out.println("---------------------------------");

        Optional<Employee> op2 =employees.parallelStream()
                .filter((e)->e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(op2.get());
    }

    @Test
    public void test2(){
        long count = employees.stream()
                .count();
        System.out.println(count);
        Optional<Employee> op1 = employees.stream()
                .max((e1,e2)->Double.compare(e1.getSlary(),e2.getSlary()));
        System.out.println(op1);
        Optional<Double> op2 = employees.stream()
                .map(Employee::getSlary)
                .min(Double::compare);
        System.out.println(op2);
    }

    /**
     * 归约
     * reduce(T identity,BinaryOperator)/reduce(BinaryOperator)--可以将流中元素反复结合起来,得到一个值。
     */
    @Test
    public void test3(){
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        Integer sum = list.stream()
                .reduce(0,(x,y)->x+y);
        System.out.println(sum);

        System.out.println("------------------------");

        Optional<Double> op = employees.stream()
                .map(Employee::getSlary)
                .reduce(Double::sum);
        System.out.println(op);
    }

    /**
     * 收集
     * collect--将流转换为其他形式,接受一个Collector接口的实现,用于给Stream中元素做汇总的方法
     */
    @Test
    public void test4(){
        List<String> list = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);

        System.out.println("-------------------");
        Set<String> set = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);
    }

    @Test
    public void test(){
        //总数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println(count);
        System.out.println("-----------------------------");
        //平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSlary));
        System.out.println(avg);
        System.out.println("-----------------------------");
        //总和
        Double sum= employees.stream()
                .collect(Collectors.summingDouble(Employee::getSlary));
        System.out.println(sum);
        System.out.println("-----------------------------");
        //最大值
        Optional<Employee> op1 = employees.stream()
                .collect(Collectors.maxBy((e1,e2)->Double.compare(e1.getSlary(),e2.getSlary())));
        System.out.println(op1.get());
        System.out.println("-----------------------------");
        //最小值
        Optional<Double> op2 = employees.stream()
                .map(Employee::getSlary)
                .collect(Collectors.minBy(Double::compare));
        System.out.println(op2);
    }

    //分组
    @Test
    public void test6(){
        Map<Employee.Status,List<Employee>> map =  employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
        for(Map.Entry<Employee.Status,List<Employee>> entry : map.entrySet()){
            System.out.println(entry);
        }
    }

    //多级分组
    @Test
    public void test7(){
        Map<Employee.Status,Map<String,List<Employee>>>map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e)->{
                    if((e).getAge()<=50){
                        return "青年";
                    }else if((e).getAge()<=50){
                        return "中年";
                    }else {
                        return "老年";
                    }
                })));
        System.out.println(map);
    }

    //分区
    @Test
    public void test8(){
        Map<Boolean,List<Employee>> map =employees.stream()
                .collect(Collectors.partitioningBy((e)->e.getSlary()>3000));
        System.out.println(map);
    }

    @Test
    public void test9(){
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSlary));
        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getMax());
    }

    @Test
    public void test10(){
        String str = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(","));
        System.out.println(str);
    }

}

5. java8的并行流采用的ForkJoin框架(java7就有了只不过用起来很麻烦)——将任务不断的拆分为更小的任务,然后将小的任务加入到线程队列中进行运算,再将结果合起来的方式;该框架的核心特点为“工作窃取模式”——当一个线程中没有任务时会随机的去其他线程的队列末尾“偷”一个任务来进行;并行流的用法在java8中得到了简化,用起来十分方便——同过Stream API 中的parallel()与sequential()即可切换并行流与顺序流

    /**
     * 并行流与顺序流的用法,以及效果演示
     */
    @Test
    public void test1(){
        //开始时间
        Instant start = Instant.now();

        // 用于计算0,到10000000000的累加和,parallel()让其使用并行流来进行运算,sequential()让其使用顺序流来进行运算
        LongStream.rangeClosed(0,10000000000L)
                .parallel()
                .reduce(0,Long::sum);

        //结束时间
        Instant end = Instant.now();

        System.out.println("耗时:"+Duration.between(start,end).toMillis()+"毫秒");
    }

6. Optional<T>类,这个类可以更好的避免空指针异常,如果发生空指针异常可以明确到具体点


public class OptionalTest {

    /*
    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
     */

    /**
     * Optional.of(T t) : 创建一个Optional实例
     * 如果传入的为空那么运行时创建实例这行会直接报错
     */
    @Test
    public void test1(){
        Optional<Employee> op = Optional.of(new Employee());
        Employee emp = op.get();
        System.out.println(emp);
    }

    /**
     * Optional.empty() : 创建一个空的Optional实例
     * 可以创建空的实例,但是空的实例是不能get()的
     */
    @Test
    public void test2(){
        Optional<Employee> op = Optional.empty();
        System.out.println(op.get());
    }

    /**
     * Optional.OfNullable(T t) : 若t不为null,创建Optional实例,否则创建空实例
     * 可以创建空的实例,但同样不能get()
     *
     * isPresent() : 判断是否包含值
     *
     * orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
     *
     * orElseGet(Supplier s) : 如果调用对象包含值,返回该值,否则返回s获得的值
     */
    @Test
    public void test3(){
        Optional<Employee> op = Optional.ofNullable(null);

        //如果op有值就进入if
        if(op.isPresent()){
            System.out.println(op.get());
        }

        //如果op中有值则emp中装的是op中的值,如果op中没有值则emp中装的是下面新new的对象
        Employee emp = op.orElse(new Employee("张三",18,4032.33,Employee.Status.FREE));
        System.out.println(emp);

        //如果op中有值则emp中装的是op中的值,如果op中没有值则emp中装的是op.orElseGet()括号中的功能
        Employee emp2 = op.orElseGet(()->new Employee());
        System.out.println(emp2);
    }

    /**
     * map(Function f) : 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty()
     *
     * flatMap(Function mapper) : 与map类似,要求返回值必须是Optional
     */
    @Test
    public void test4(){
        Optional<Employee> op = Optional.ofNullable(new Employee("张三",18,4032.33,Employee.Status.FREE));

        //将容器中的对象应用到了map中的函数上
        Optional<String> str = op.map((e)->e.getName());
        System.out.println(str.get());

        //要求必须将结果包装的Optional中
        Optional<String> str2 = op.flatMap((e)->Optional.of(e.getName()));
        System.out.println(str2.get());
    }

}

7. java8接口中允许有默认方法——用default修饰的接口它的实现方法可以直接写在接口中,当这个接口被调用时遵从“类优先”的原则;接口中还允许有静态方法。

8. java8出了一套全新的时间日期API,以解决线程安全问题。

8.1 新时间API的本地时间与时间戳

public class LocalDatetimeTest {

    /**
     * LocalData 日期
     * LocalTieme 时间
     * LocalDateTime 日期时间
     *
     * 这三个的用法一样
     */
    @Test
    public void test1(){
        //获取当前时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        //创建一个时间
        LocalDateTime ldt2= LocalDateTime.of(2020,12,12,0,0,0);
        System.out.println(ldt2);

        //加一个小时
        LocalDateTime ldt3 = ldt2.plusHours(1);
        System.out.println(ldt3);

        //减8分钟
        LocalDateTime ldt4 = ldt3.minusMinutes(8);
        System.out.println(ldt4);

        //对时间拆分
        System.out.println(ldt.getYear()+"年");
        System.out.println(ldt.getMonthValue()+"月");
        System.out.println(ldt.getDayOfMonth()+"日");
    }

    /**
     * Instant : 时间戳(以 Unix 元年:1970年1月1日00:00:00 到某一个时间之间的毫秒值)
     */
    @Test
    public void test2(){
        //默认的是 UTC 时区
        Instant ins1 = Instant.now();
        System.out.println(ins1);

        //做偏移量运算
        OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
        System.out.println(odt);

        //显示毫秒
        System.out.println(ins1.toEpochMilli());

        //从Unix元年开始做运算
        Instant ins2 = Instant.ofEpochSecond(1);
        System.out.println(ins2);
    }

    /**
     * Duration:计算两个“时间”之间的间隙
     * Period:计算两个“日期”之间的间隙
     */
    @Test
    public void test3() throws InterruptedException {
        Instant ins1 = Instant.now();
        Thread.sleep(1000);
        Instant ins2 = Instant.now();

        Duration duration = Duration.between(ins1,ins2);
        System.out.println(duration.toMillis());

        System.out.println("---------------------------------");

        LocalTime lt1 = LocalTime.now();
        Thread.sleep(1000);
        LocalTime lt2 = LocalTime.now();

        System.out.println( Duration.between(lt1,lt2));

        System.out.println("---------------------------------");

        LocalDate ld1 = LocalDate.of(2011,2,5);
        LocalDate ld2 = LocalDate.now();

        Period period = Period.between(ld1,ld2);
        System.out.println(period);

        System.out.println(period.getYears());
        System.out.println(period.getMonths());
        System.out.println(period.getDays());
    }
}

8.2 时间校正器

    /**
     * TemporalAdjuster:时间校正器
     */
    @Test
    public void test4(){
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);
        
        //十月的这一天
        LocalDateTime ldt2 = ldt.withDayOfMonth(10);
        System.out.println(ldt2);

        //下一个星期天
        LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
        System.out.println(ldt3);

    }

8.3 时间的格式化

    /**
     * DataTimeFormatter:格式化时间/日期
     */
    @Test
    public void test6(){
        //使用系统自带的格式
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
        LocalDateTime ldt = LocalDateTime.now();

        String strData = ldt.format(dtf);
        System.out.println(strData);

        System.out.println("---------------------");

        //使用自定义的格式
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");

        String strData2 = ldt.format(dtf2);
        System.out.println(strData2);

        //将格式解析回默认的
        LocalDateTime newDate = ldt.parse(strData2,dtf2);
        System.out.println(newDate);

    }

8.4 时区的处理

    /**
     * ZonedDate、ZonedTime、ZoneDateTime
     */
    @Test
    public void test7(){
        //查看支持的时区
        Set<String> set = ZoneId.getAvailableZoneIds();
        set.forEach(System.out::println);

        //选择的时区
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("America/New_York"));
        System.out.println(ldt);

        LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("America/New_York"));
        ZonedDateTime zdt = ldt2.atZone(ZoneId.of("America/New_York"));
        System.out.println(zdt);

    }

9. java8对注解的改进,重复注解(一个类上可以重复的定义两次注解)与类型注解(java8没有内置,需要配合一些其他的框架使用);重复注解要想使用需要用@Repeatable来修饰该注解,并指定容器类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值