继续着上次的java完全解读一

1.强大的Stream API

Stream 是Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL 执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

1.1什么是Stream

流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。

“集合讲的是数据,流讲的是计算!”

注意:

①Stream 自己不会存储元素。

②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。

③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。

1.2 Stream操作的三大步骤

  • 创建Stream

    一个数据源(如:集合、数组),获取一个流
  • 中间操作

    一个中间操作链,对数据源的数据进行处理
  • 终止操作(终端操作)

    一个终止操作,执行中间操作链,并产生结果

1.2.1 创建Stream

创建Stream严格来说有三种方式

  • Java8 中的Collection 接口被扩展,提供了两个获取流的方法:
//Collection的方法
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
  • Java8 中的Arrays的静态方法stream() 可以获取数组流:
  • 可以使用静态方法Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数
//Arrays的方法
static <T> Stream<T> stream(T[] array);// 返回一个流
//Stream的方法
public static<T> Stream<T> of(T… values);// 返回一个流
  • 可以使用静态方法Stream.iterate()Stream.generate(), 创建无限流。
//迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//生成
public static<T> Stream<T> generate(Supplier<T> s) :
/*
*UnaryOperator是传入类型T返回类型T
* Supplier是无参,返回类型T
*/

实际运用

public void test1(){
        /**
        * list中的数据本来是用List包裹,创建stream后,将list中的数据换成了stream包裹了,
        * 同时对流中的数据操作变得更加方便
        */
        //1. Collection 提供了两个方法  stream() 与 parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.stream(); //获取一个顺序流
        Stream<String> parallelStream = list.parallelStream(); //获取一个并行流

        //2. 通过 Arrays 中的 stream() 获取一个数组流
        Integer[] nums = new Integer[10];
        Stream<Integer> stream1 = Arrays.stream(nums);
        //通过 Stream 类中静态方法 of()底层也是调用
        Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);

        //3.创建无限流,这两个底层调用的都是一样的
        //迭代
        Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
        stream3.forEach(System.out::println);
        //生成
        Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
        stream4.forEach(System.out::println);
    }

1.2.2 Stream的中间操作

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

筛选和切片

运用

//筛选年龄<=35岁的员工
@Test
public void test2(){
    //所有的中间操作不会做任何的处理
    Stream<Employee> stream = emps.stream()
            .filter((e) -> {
                System.out.println("测试中间操作");
                return e.getAge() <= 35;
         });
   //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
   stream.forEach(System.out::println);
}

//查询薪水>=5000的前三个员工
@Test
public void test4(){
      emps.stream()
            .filter((e) -> {
             return e.getSal() >= 5000;
      }).limit(3)
            .forEach(System.out::println);
  }

//查询薪水>=5000的员工,去掉前两个
    @Test
    public void test5(){
        emps.stream()
                .filter((e) -> e.getSal()>= 5000)
                .skip(2)//跳过2元素,返回一个扔掉了前2个元素的流
                .forEach(System.out::println);
    }

//去重
@Test
public void test6(){
     emps.stream()
            .distinct()
            .forEach(System.out::println);
  }
映射

实例运用

  • map
@Test
    public void test1() {
        List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        //将传入的String值转为大写并返回String
        Stream<String> stream = strList.stream()
                .map(String::toUpperCase);
        stream.forEach(System.out::println);
        //传入的String,通过方法将String转化成包裹字符的stream了
        Stream<Stream<Character>> stream2 = strList.stream()
                .map(Stream2::filterCharacter);
        stream2.forEach((sm) -> {
            sm.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();
    }
  • flatMap
//flatmap
    @Test
    public void Test3() {
        List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        Stream<Character> stream3 = strList.stream()
                .flatMap(Stream2::filterCharacter);
        stream3.forEach(System.out::println);
    }
排序



实际运用

@Test
    public void test3() {
        emps.stream()
                .map(Employee::getName)
                .sorted()
                .forEach(System.out::println);
        emps.stream()//按年龄排序,如果年龄相同:按名字排序
                .sorted((x, y) -> {
                    if (x.getAge() == y.getAge()) {
                        return x.getName().compareTo(y.getName());
                    } else {
                        return Integer.compare(x.getAge(), y.getAge());
                    }
                }).forEach(System.out::println);
    }

1.2.3 Stream 的终止操作

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void 。

查找与匹配

归约



备注:map 和reduce 的连接通常称为map-reduce 模式,因Google 用它来进行网络搜索而出名。

使用

    @Test
    public void test1(){
        //将数组中的值加起来
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(sum);
        //使用map将员工的工资提取出来,使用reduce将工资累加
        Optional<Double> op = emps.stream()
                .map(Employee::getSal)
                .reduce(Double::sum);
        System.out.println(op.get());
    }
    //需求:搜索名字中 “六” 出现的次数
    @Test
    public void test2(){
        Optional<Integer> sum = emps.stream()
                .map(Employee::getName)
                .flatMap(Stream2::filterCharacter)
                .map((ch) -> {
                    if(ch.equals('六'))
                        return 1;
                    else
                        return 0;
                }).reduce(Integer::sum);

        System.out.println(sum.get());
    }
收集

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:



2 新时间日期API

2.1 使用LocalDate、LocalTime、LocalDateTime

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。

提供的方法:

运用

@Test
    public void test() {
        LocalDate localDate = LocalDate.now();//现在的日期
        LocalTime localTime = LocalTime.now();//现在的时间
        LocalDateTime localDateTime = LocalDateTime.now();//现在的时间和日期
        System.out.println(localDate+"==>"+localTime+"==>"+localDateTime);
    }
    @Test
    public void test2() {
        LocalDate localDate = LocalDate.of(1996, 02, 03);//指定现在的日期
        LocalTime localTime = LocalTime.of(16, 04);//指定现在的时间
        LocalDateTime localDateTime = LocalDateTime.of(1996, 02, 03, 16, 04);//指定现在的日期时间
        System.out.println(localDate+"==>"+localTime+"==>"+localDateTime);
    }
    @Test
    public void test3() {
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = localDate.plusDays(5);//在当前时间上加5天
        LocalDate localDate2 = localDate.plusMonths(2);//加2个月
        LocalDate localDate3 = localDate.plusWeeks(1);//加一周
        LocalDate localDate4 = localDate.plusYears(1);//加一年
        LocalDate localDate5 = localDate.minusMonths(5);//减5天
        System.out.println(localDate4);
    }

    @Test
    public void test5() {
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = localDate.withDayOfMonth(12);//将日期中的,这个月的天数修改为12
        LocalDate localDate2 = localDate.withYear(2015);//将日期中的年修改为2015
        LocalDate localDate3 = localDate.withMonth(8);//将日期中的月修改为8月
        System.out.println(localDate3);
    }
    @Test
    public void test6() {
        LocalDate localDate = LocalDate.now();
        int year = localDate.getYear();//获取当前的年份
        System.out.println(year);
    }
    @Test
    public void test7() {
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = LocalDate.now();
        Period period = localDate.until(localDate1);//获取两个日期间的日期间隔
        boolean before = localDate.isBefore(localDate1);//比较两个localData
        boolean leapYear = localDate.isLeapYear();//是否是闰年
        System.out.println(before);
    }

2.2 Duration 和Period

  • Duration:用于计算两个“时间”间隔
  • Period:用于计算两个“日期”间隔

使用

@Test
    public void test4() {
        //时间戳
        Instant start = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }
        Instant end = Instant.now();
        //Duration:用于计算两个“时间”间隔
        Duration duration = Duration.between(start, end);
        // Period:用于计算两个“日期”间隔
        LocalDate localDate = LocalDate.now();
        LocalDate localDate1 = LocalDate.of(2017, 12, 1);
        Period period = Period.between(localDate, localDate1);
        //给日期加一个间隔
        LocalDate localDate3 = localDate.plus(period);
        System.out.println(localDate3);
    }

2.3 解析与格式化

使用java.time.format.DateTimeFormatter对时间和日期进行格式化

@Test
    public void test8() {
        LocalDateTime localDateTime = LocalDateTime.now();
        //第一种对时间日期的格式化方式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yy年MM月dd日 HH:mm:ss");
        String format = formatter.format(localDateTime);
        System.out.println(format);
        //第二种对时间日期的格式化方式
        String format1 = localDateTime.format(DateTimeFormatter.ofPattern("yy年MM月dd日"));
        System.out.println(format1);
    }

2.4 时区的处理

Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式例如:Asia/Shanghai 等

@Test
    public void test9() {
        //时区
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        System.out.println(ldt);
    }

3 接口中的默认方法与静态方法

3.1 接口中的默认方法

Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用default关键字修饰.

3.1.1 默认方法的使用

public interface MyInterface {
    default String getName(){
        return "呵呵呵";
    }
}

一个实现这个接口的类

public class SubClass implements MyInterface{
}

在主函数中调用

public static void main(String[] args) {
        SubClass sc = new SubClass();
        System.out.println(sc.getName());
    }

打印结果呵呵呵

3.1.2 接口默认方法的”类优先”原则

这时假如这个子类有一个父类,父类中也有一个getName()方法

public class MyClass {
    public String getName(){
        return "嘿嘿嘿";
    }
}

子类此时是

public class SubClass extends MyClass implements MyInterface{
}

这时在主类中掉用

public static void main(String[] args) {
        SubClass sc = new SubClass();
        System.out.println(sc.getName());
    }

结果为嘿嘿嘿

类优先原则:若一个接口中定义了一个默认方法,而另外一个父类中又定义了一个同名的方法时.

选择父类中的方法。如果父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。

3.1.3 接口默认方法的"接口冲突"

"接口冲突":假如子类实现的多个接口中有相同的方法和参数(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突

如,子类的另一个实现的接口

public interface MyFun {
    default String getName(){
        return "哈哈哈";
    }
}

这时子类必须覆盖方法,通过接口名来指定到底调用哪一个

public class SubClass implements MyFun,MyInterface{
    @Override
    public String getName() {
        return MyInterface.super.getName();//指定调用的接口
    }
}

在主类中调用

public static void main(String[] args) {
        SubClass sc = new SubClass();
        System.out.println(sc.getName());
    }

执行结果:呵呵呵

3.2 接口中的静态方法

Java8 中,接口中允许添加静态方法。

使用

public interface MyInterface {
    static void show(){
        System.out.println("接口中的静态方法");
    }
}

直接使用类名调用

public static void main(String[] args) {
        MyInterface.show();
    }

输出结果:接口中的静态方法

java8完全解读二的更多相关文章

  1. java8完全解读一

    java8完全解读 java8完全解读前言java8的一些新特性1.为什么要用java8?1.1首先想到的逻辑应该是如下1.2使用策略模式来解这个问题1.3使用策略模式和内部类来解决问题1.4使用策略 ...

  2. jQuery.Callbacks 源码解读二

    一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...

  3. java多线程解读二(内存篇)

    线程的内存结构图 一.主内存与工作内存 1.Java内存模型的主要目标是定义程序中各个变量的访问规则.此处的变量与Java编程时所说的变量不一样,指包括了实例字段.静态字段和构成数组对象的元素,但是不 ...

  4. mybatis源码解读(二)——构建Configuration对象

    Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...

  5. (转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin

    转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...

  6. cJONS序列化工具解读二(数据解析)

    cJSON数据解析 关于数据解析部分,其实这个解析就是个自动机,通过递归或者解析栈进行实现数据的解析 /* Utility to jump whitespace and cr/lf *///用于跳过a ...

  7. NSObject头文件解析 / 消息机制 / Runtime解读 (二)

    本章接着NSObject头文件解析 / 消息机制 / Runtime解读(一)写 给类添加属性: BOOL class_addProperty(Class cls, const char *name, ...

  8. Nginx 小入门记录 之 Nginx 配置文件解读(二)

    上一小节主要是记录一些环境准备和Nginx的安装,接下来对Nginx基本配置进行记录. 查看配置文件安装记录 可以通过以下Linux命令进行查看: rpm -ql nginx rpm 是liunx的包 ...

  9. 20190925 On Java8 第二十二章 枚举

    第二十二章 枚举 基本 enum 特性 创建 enum 时,编译器会为你生成一个相关的类,这个类继承自 Java.lang.Enum. valueOf() 是在 Enum 中定义的 static 方法 ...

随机推荐

  1. Oracle R12 多组织访问的控制 - MOAC(Multi-Org Access Control)

    什么是MOAC MOAC(Multi-Org Access Control)为多组织访问控制,是Oracle EBS R12的重要新功能,它可以实现在一个Responsibility下对多个Opera ...

  2. OpenCV导向滤波(引导滤波)实现(Guided Filter)代码,以及使用颜色先验算法去雾

    论文下载地址:http://research.microsoft.com/en-us/um/people/jiansun/papers/GuidedFilter_ECCV10.pdf 本文主要介绍导向 ...

  3. 理解WebKit和Chromium: Chromium插件和扩展基础

    转载请注明原文地址:http://blog.csdn.net/milado_nju ##概述 插件和扩展是一种扩充浏览器功能的技术,在之前我们介绍过NPAPI插件技术,在Chromium中,远远不只是 ...

  4. Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置

    Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这 ...

  5. 总账追朔各模块SQL

    SELECT gjh.set_of_books_id, gjl.je_line_num, mta.organization_id, ood.organization_code, ood.organiz ...

  6. 页面缓存js问题解决

     1.在jsp中加入头 <META HTTP-EQUIV="Pragma" CONTENT="no-cache">  <META HTTP ...

  7. UTF-8是现在流行的编码方式,根据规定回答问题

    UTF-8是现在流行的编码方式,下面是RFC2279对UTF-8编码规则的规定 UCS-4 range (hex.) UTF-8 octet sequence (binary) 0000 0000-0 ...

  8. Working with bounded Task Flows

      Working with Bounded Task Flows, Regions and Routers in JDeveloper 11g Purpose In this tutorial, y ...

  9. Gradle 1.12用户指南翻译——第四十一章. 项目报告插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  10. PS图像特效算法——百叶窗

    这个只要设置好条纹的宽度和条纹的间隔,建立一个遮罩层,等间隔的对原图进行等间距的遮罩. clc; clear all; Image=imread('4.jpg'); Image=double(Imag ...