jdk1.8新特性

历史:

openjdk->sun公司开发的

oracle收购sun公司

Oraclejdk->oracle公司开发,基于openjdk

lambda表达式

public class a{
   public static void main(String[] args){
       //开启一个线程
       new Thread(new Runnable(){
           public void run(){
               System.out.println("线程运行");
          }
      }).start();
       System.out.println("主线程运行");
  }
}

注解

@FunctionallInterface :类注解,只允许类有一个抽象方法
lambda表达式原理

编译时生成一个匿名内部类。

 

接口

jdk1.8之前只有1.常量2.抽象方法

jdk1.8之后可以有1.常量2.抽象方法3.默认方法4.静态方法

 

Stream流

fliter:

public class StreamFilter {
   public static void main(String[] args) {
       List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       //1.获取所有姓张的信息
       //2.获取名称长度为3的用户
       //3.输出所有的用户信息
       ArrayList<Object> list1 = new ArrayList<>();
       for (String s : list) {
           if (s.startsWith("张") && s.length()==3){
               list1.add(s);
          }
      }
       for (Object o : list1) {
           System.out.println(o);
      }
       //stream流
       list.stream()
              .filter(a->a.startsWith("张"))
              .filter(a->a.length()==3)
              .forEach(System.out::println);
  }
}

stream流的获取方式

  1. 根据Collection获取

Collection接口增加了一个default接口

new ArrayList().stream();
new HashSet().stream();
...
map集合没有实现Collection接口,不能直接使用,可以转为set集合使用
  1. 通过Steam的of方法(主要操作数组)

    Steam接口有一个静态方法of()

String[] arr1={"aa","bb","cc"};
Stream.of(arr1);
Stream a1=Stream.off("a1","a2","a3");
//注意:基本数据类型的数组是不可以的

forEach

forEach用来遍历集合

        //stream流
       List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       list.stream().forEach(System.out::println);

count

统计元素的个数

List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       list.stream().count();

fliter

过滤数据,返回符合条件的数据

List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       //stream流
       list.stream()
              .filter(a->a.startsWith("张"))
              .filter(a->a.length()==3)
              .forEach(System.out::println);

limit

分页,取前n个数据

List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       list.stream().limit(2).forEach(System.out::println);

skip

跳过前n个数据

 List<String> list = Arrays.asList("张三", "张三丰", "李四", "王五");
       list.stream().skip(2).forEach(System.out::println);

map

类型转换,一种类型转换为另一种,包括基本类型和对象类型

Stream.of("1","2","3","4","5","6")
              .map(Integer::parseInt)
              .forEach(System.out::println);

sorted

排序

//自然排序
       Stream.of("1","2","3","4","5","6")
              .map(Integer::parseInt)
              .sorted()
              .forEach(System.out::println);
       System.out.println("降序");
       Stream.of("1","2","3","4","5","6")
              .map(Integer::parseInt)
              .sorted((a,b)->{return b-a;})
              .forEach(System.out::println);

distinct

去除重复

//去重
       Stream.of("1","2","2","3","3","4","5","6")
              .map(Integer::parseInt)
              .distinct()
              .forEach(System.out::println);

如果是对象的话根据对象的的hashcode和equals方法判断

flatMap 使用

flatMap 方法用于映射每个元素到对应的结果,一对多。

示例:从句子中得到单词

 String worlds = "The way of the future";
List<String> list7 = new ArrayList<>();
list7.add(worlds);
List<String> list8 = list7.stream().flatMap(str -> Stream.of(str.split(" ")))
  .filter(world -> world.length() > 0).collect(Collectors.toList());
System.out.println("单词:");
list8.forEach(System.out::println);
// 单词:
// The
// way
// of
// the
// future

Stream流的peek使用

peek对每个元素执行操作并返回一个新的Stream

示例: 双重操作

 System.out.println("peek使用:");
Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("转换之前: " + e))
  .map(String::toUpperCase).peek(e -> System.out.println("转换之后: " + e)).collect(Collectors.toList());

// 转换之前: three
// 转换之后: THREE
// 转换之前: four
// 转换之后: FOUR

Stream流的Match使用

  • allMatch:Stream 中全部元素符合则返回 true ;

  • anyMatch:Stream 中只要有一个元素符合则返回 true;

  • noneMatch:Stream 中没有一个元素符合则返回 true。

示例:数据是否符合

 boolean all = lists.stream().allMatch(u -> u.getId() > 3);
System.out.println("是否都大于3:" + all);
boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
System.out.println("是否有一个大于3:" + any);
boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
System.out.println("是否没有一个大于3的:" + none);  
// 是否都大于3:false
// 是否有一个大于3:true
// 是否没有一个大于3的:false

Stream流的iterate使用

iterate 跟 reduce 操作很像,接受一个种子值,和一个UnaryOperator(例如 f)。然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。在 iterate 时候管道必须有 limit 这样的操作来限制 Stream 大小。

示例:生成一个等差队列

 System.out.println("从2开始生成一个等差队列:");
Stream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + " "));
// 从2开始生成一个等差队列:
// 2 4 6 8 10

 

reduce

Integer reduce = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::parseInt)
              .reduce(0, (a, b) -> a + b);//求和   0+1+2+2+3+3+4+5+6
       System.out.println(reduce);

map+reduce

Integer a=Stream.of(
         new Person("zhangsan",18)
        ,new Person("zhangsan",18)
        ,new Person("zhangsan",18)
        ,new Person("zhangsan",18))
        .map(p->p.getAge())
  .reduce(0,(a,b)->a+b);
System.out.println(a);

mapToInt

Integer  arr[]={1,2,3,5,6,8};
IntStream int=Stream.off(arr)
  .mapToInt(Integer::intValue);

concat

两个流合并成一个流可以使用

Stream<String> a=Stream.of("a","b","c");
Stream<String> b=Stream.of("x","y","z");
Stream.concat(a,b).forEach(System.out::println);

Stream结果收集

1.到集合

List<Integer> list = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::parseInt)
              .collect(Collectors.toList());
Set<Integer> set = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::parseInt)
              .collect(Collectors.toSet());
ArrayList<Integer> arrayList = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::parseInt)
              .collect(Collectors.toCollection(ArrayList::new));
HashSet<Integer> hasSet = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::parseInt)
              .collect(Collectors.toCollection(HashSet::new));

2.到数组

Object[] objects = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .toArray();
Integer[] array = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .toArray(Integer[]::new);

3.对流中的数据进行聚合计算

sum max min avg count

max

Optional<Integer> collect = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::valueOf)
              .collect(Collectors.maxBy((a, b) -> a - b));

min

Optional<Integer> collect = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::valueOf)
              .collect(Collectors.maxBy((a, b) -> b-a));

sum

Integer collect = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::valueOf)
                      .collect(Collectors.summingInt(a->a));
       System.out.println(collect);

avg

Double collect = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::valueOf)
                      .collect(Collectors.averagingInt(a->a));
       System.out.println(collect);

count

 Long collect = Stream.of("1", "2", "2", "3", "3", "4", "5", "6")
              .map(Integer::valueOf)
                      .collect(Collectors.counting());
       System.out.println(collect);

4.对流中的数据做分组操作

4.1一个字段

        List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 93, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 64, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 60, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       Map<String, List<PeoplePO>> collect = list.stream().collect(Collectors.groupingBy(PeoplePO::getName));
       collect.forEach((k,v)->System.out.println(k+":"+v));
Map<String, List<PeoplePO>> map = list.stream().collect(Collectors.groupingBy(a -> a.getAge() >= 18 ? "成年" : "未成年"));
       map.forEach((k,v)->System.out.println(k+":"+v));

4.2多级分组

List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       Map<String, Map<String, List<PeoplePO>>> collect = list.stream()
              .collect(Collectors.groupingBy(PeoplePO::getName, Collectors.groupingBy(p -> p.getAge() > 18 ? "成年" : "未成年")));
       collect.forEach((k,v)-> System.out.println(k+":"+v));

5.分区

 List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       list.stream().collect(Collectors.partitioningBy(p->p.getAge()>18)).forEach((k,v)->System.out.println(k+":"+v));

6.拼接

 List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       String collect = list.stream().map(PeoplePO::getName).collect(Collectors.joining());
       System.out.println(collect);
       String collect2 = list.stream().map(PeoplePO::getName).collect(Collectors.joining("_"));
       System.out.println(collect2);
       String collect3 = list.stream().map(PeoplePO::getName).collect(Collectors.joining("_","pre","suf"));
       System.out.println(collect3);

Stream并行和串行流

前面使用的都是串行流

1.串行流

List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       list.stream().filter(a->{
           System.out.println(Thread.currentThread());
           return a.getAge()>18;}).count();
//都在一个线程执行

2.并行流

parallelStream并行流

2.1获取

List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
//1.直接获取
       Stream<PeoplePO> parallelStream = list.parallelStream();
//2.转换获取
       Stream<PeoplePO> parallel = list.stream().parallel();

2.2操作

List<PeoplePO> list = new ArrayList<>();
       list.add(new PeoplePO("张三", 3, 50.0));
       list.add(new PeoplePO("李四", 53, 60.84));
       list.add(new PeoplePO("王五", 30, 30.0));
       list.add(new PeoplePO("赵六", 5, 230.5));
       list.add(new PeoplePO("周七", 18, 88.0));
       list.add(new PeoplePO("老八", 17, 23.0));
       list.add(new PeoplePO("狗九", 29, 17.34));
       list.parallelStream().filter(
               a->{
                   System.out.println(Thread.currentThread());
                   return a.getAge()>18;
              }
      ).count();

fork/join并行流底层算法

Optional类(处理空指针)

1.以前

 String a =null;
       if (a != null) {
           System.out.println(a.length());
      } else {
           System.out.println("sda");
      }

2.Optional类

       //of方法
       Optional<String> optional = Optional.of("zhangsan");
       //Optional<Object> o = Optional.of(null); 不支持传入空
       //ofNullable方法
       Optional<String> zhangsan = Optional.ofNullable("zhangsan");
       Optional<Object> o = Optional.ofNullable(null); //支持null
       //empty
       Optional<Object> empty = Optional.empty();

获取值

//of方法
       Optional<String> optional = Optional.of("zhangsan");
       //Optional<Object> o = Optional.of(null); 不支持传入空
       System.out.println(optional.get());
       //ofNullable方法
       Optional<String> zhangsan = Optional.ofNullable("zhangsan");
       Optional<Object> o = Optional.ofNullable(null); //支持null
       System.out.println(o.get());//NoSuchElementException: No value present
       //empty
       Optional<Object> empty = Optional.empty();

提高:

isPresent():是否包含值

.orElse():如果包含值返回值,否则返回指定值

  //of方法
       Optional<String> optional = Optional.of("zhangsan");
       //Optional<Object> o = Optional.of(null); 不支持传入空
       if(optional.isPresent()){
           System.out.println(optional.get());
      }
       //ofNullable方法
       Optional<String> zhangsan = Optional.ofNullable("zhangsan");
       Optional<Object> o = Optional.ofNullable(null); //支持null
       if(o.isPresent()){
           System.out.println(o.get());
      }
System.out.println(o.orElse("aa"));
       //empty
       Optional<Object> empty = Optional.empty();

LocalDateTime

格式化

LocalDateTime now = LocalDateTime.now();
       DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
       DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
       System.out.println(now.format(isoLocalDateTime));
       System.out.println(now.format(dateTimeFormatter));
       LocalDateTime parse = LocalDateTime.parse("2020-01-01 12:00:00", dateTimeFormatter);
       System.out.println(parse);

介绍

JDK1.8除了新增了lambda表达式、stream流之外,它还新增了全新的日期时间API。在JDK1.8之前,Java处理日期、日历和时间的方式一直为社区所诟病,将 java.util.Date设定为可变类型,以及SimpleDateFormat的非线程安全使其应用非常受限。因此推出了java.time包,该包下的所有类都是不可变类型而且线程安全。

关键类

  • Instant:瞬时时间。

  • LocalDate:本地日期,不包含具体时间, 格式 yyyy-MM-dd。

  • LocalTime:本地时间,不包含日期. 格式 yyyy-MM-dd HH:mm:ss.SSS 。

  • LocalDateTime:组合了日期和时间,但不包含时差和时区信息。

  • ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差。

使用

1.获取当前的日期时间

通过静态工厂方法now()来获取当前时间。

 //本地日期,不包括时分秒
LocalDate nowDate = LocalDate.now();
//本地日期,包括时分秒
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("当前时间:"+nowDate);
System.out.println("当前时间:"+nowDateTime);
// 当前时间:2018-12-19
// 当前时间:2018-12-19T15:24:35.822

2.获取当前的年月日时分秒

获取时间之后,直接get获取年月日时分秒。

  //获取当前的时间,包括毫秒
LocalDateTime ldt = LocalDateTime.now();
System.out.println("当前年:"+ldt.getYear());   //2018
System.out.println("当前年份天数:"+ldt.getDayOfYear());//172
System.out.println("当前月:"+ldt.getMonthValue());
System.out.println("当前时:"+ldt.getHour());
System.out.println("当前分:"+ldt.getMinute());
System.out.println("当前时间:"+ldt.toString());
//   当前年:2018
//   当前年份天数:353
//   当前月:12
//   当前时:15
//   当前分:24
//   当前时间:2018-12-19T15:24:35.833

3.格式化时间

格式时间格式需要用到DateTimeFormatter类。

LocalDateTime ldt = LocalDateTime.now();
System.out.println("格式化时间: "+ ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
//格式化时间:2018-12-19 15:37:47.119

4.时间增减

在指定的时间进行增加/减少年月日时分秒。

  LocalDateTime ldt = LocalDateTime.now();
System.out.println("后5天时间:"+ldt.plusDays(5));
System.out.println("前5天时间并格式化:"+ldt.minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); //2018-06-16
System.out.println("前一个月的时间:"+ldt2.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyyMM"))); //2018-06-16
System.out.println("后一个月的时间:"+ldt2.plusMonths(1)); //2018-06-16
System.out.println("指定2099年的当前时间:"+ldt.withYear(2099)); //2099-06-21T15:07:39.506
// 后5天时间:2018-12-24T15:50:37.508
// 前5天时间并格式化:2018-12-14
// 前一个月的时间:201712
// 后一个月的时间:2018-02-04T09:19:29.499
// 指定2099年的当前时间:2099-12-19T15:50:37.508

5.创建指定时间

通过指定年月日来创建。

 LocalDate ld3=LocalDate.of(2017, Month.NOVEMBER, 17);
LocalDate ld4=LocalDate.of(2018, 02, 11);

6.时间相差比较

比较相差的年月日时分秒。

示例一: 具体相差的年月日

 LocalDate ld=LocalDate.parse("2017-11-17");
LocalDate ld2=LocalDate.parse("2018-01-05");
Period p=Period.between(ld, ld2);
System.out.println("相差年: "+p.getYears()+" 相差月 :"+p.getMonths() +" 相差天:"+p.getDays());
// 相差年: 0 相差月 :1 相差天:19

注:这里的月份是不满足一年,天数是不满足一个月的。这里实际相差的是1月19天,也就是49天。

示例二:相差总数的时间

ChronoUnit 日期周期单位的标准集合。

    LocalDate startDate = LocalDate.of(2017, 11, 17);
      LocalDate endDate = LocalDate.of(2018, 01, 05);
      System.out.println("相差月份:"+ChronoUnit.MONTHS.between(startDate, endDate));
      System.out.println("两月之间的相差的天数   : " + ChronoUnit.DAYS.between(startDate, endDate));
//       相差月份:1
//       两天之间的差在天数   : 49

注:ChronoUnit也可以计算相差时分秒。

示例三:精度时间相差

Duration 这个类以秒和纳秒为单位建模时间的数量或数量。

 Instant inst1 = Instant.now();
  System.out.println("当前时间戳 : " + inst1);
  Instant inst2 = inst1.plus(Duration.ofSeconds(10));
  System.out.println("增加之后的时间 : " + inst2);
  System.out.println("相差毫秒 : " + Duration.between(inst1, inst2).toMillis());
  System.out.println("相毫秒 : " + Duration.between(inst1, inst2).getSeconds());
// 当前时间戳 : 2018-12-19T08:14:21.675Z
// 增加之后的时间 : 2018-12-19T08:14:31.675Z
// 相差毫秒 : 10000
// 相毫秒 : 10

示例四:时间大小比较

  LocalDateTime ldt4 = LocalDateTime.now();
LocalDateTime ldt5 = ldt4.plusMinutes(10);
System.out.println("当前时间是否大于:"+ldt4.isAfter(ldt5));
System.out.println("当前时间是否小于"+ldt4.isBefore(ldt5));
// false
// true

7.时区时间计算

得到其他时区的时间。

示例一:通过Clock时钟类获取计算

Clock时钟类用于获取当时的时间戳,或当前时区下的日期时间信息。

  Clock clock = Clock.systemUTC();
System.out.println("当前时间戳 : " + clock.millis());
Clock clock2 = Clock.system(ZoneId.of("Asia/Shanghai"));
System.out.println("亚洲上海此时的时间戳:"+clock2.millis());
Clock clock3 = Clock.system(ZoneId.of("America/New_York"));
System.out.println("美国纽约此时的时间戳:"+clock3.millis());
// 当前时间戳 : 1545209277657
// 亚洲上海此时的时间戳:1545209277657
// 美国纽约此时的时间戳:1545209277658

示例二: 通过ZonedDateTime类和ZoneId

  ZoneId zoneId= ZoneId.of("America/New_York");
ZonedDateTime dateTime=ZonedDateTime.now(zoneId);
System.out.println("美国纽约此时的时间 : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
System.out.println("美国纽约此时的时间 和时区: " + dateTime);
// 美国纽约此时的时间 : 2018-12-19 03:52:22.494
// 美国纽约此时的时间 和时区: 2018-12-19T03:52:22.494-05:00[America/New_York]

Java 8日期时间API总结:

  • 提供了javax.time.ZoneId 获取时区。

  • 提供了LocalDate和LocalTime类。

  • Java 8 的所有日期和时间API都是不可变类并且线程安全,而现有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非线程安全的。

  • 主包是 java.time,包含了表示日期、时间、时间间隔的一些类。里面有两个子包java.time.format用于格式化, java.time.temporal用于更底层的操作。

  • 时区代表了地球上某个区域内普遍使用的标准时间。每个时区都有一个代号,格式通常由区域/城市构成(Asia/Tokyo),在加上与格林威治或 UTC的时差。例如:东京的时差是+09:00。

  • OffsetDateTime类实际上组合了LocalDateTime类和ZoneOffset类。用来表示包含和格林威治或UTC时差的完整日期(年、月、日)和时间(时、分、秒、纳秒)信息。

  • DateTimeFormatter 类用来格式化和解析时间。与SimpleDateFormat不同,这个类不可变并且线程安全,需要时可以给静态常量赋值。DateTimeFormatter类提供了大量的内置格式化工具,同时也允许你自定义。在转换方面也提供了parse()将字符串解析成日期,如果解析出错会抛出DateTimeParseException。DateTimeFormatter类同时还有format()用来格式化日期,如果出错会抛出DateTimeException异常。

  • 再补充一点,日期格式“MMM d yyyy”和“MMM dd yyyy”有一些微妙的不同,第一个格式可以解析“Jan 2 2014”和“Jan 14 2014”,而第二个在解析“Jan 2 2014”就会抛异常,因为第二个格式里要求日必须是两位的。如果想修正,你必须在日期只有个位数时在前面补零,就是说“Jan 2 2014”应该写成 “Jan 02 2014”。

  •