19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)

简介: 19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)

本篇是Java基础篇分篇章最后一章

接下来会沉浸一小段时间,整理一份整合起来的大约有12w+词,40w+字符的Java基础篇Markdown笔记,并且将前期缺少的部分知识点和案例也陆续完善进去

后续更新一些综合案例和LeetCode算法题,以及Javaweb部分的框架体系等等,或许也会有一些其他杂七杂八的东西(碎碎念)

记录成长-第一阶段勉勉强强给自己打分70分


19.1 Java8概述


Java8 (又称 JKD1.8) 是 Java 语言开发的一个主要版本。

Oracle公司于2014年3月18日发布Java8 。

  • 支持Lambda表达式
  • 函数式接口
  • 新的Stream API
  • 新的日期 API
  • 其他特性

19.2 Lambda表达式


19.2.1 概念

  • Lambda表达式是特殊的匿名内部类,语法更简洁。
  • Lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。

19.2.2 语法

<函数式接口> <变量名> = (参数1,参数2…) -> {

//方法体

};

19.2.3 基本使用

演示案例:

public class Demo1 {
  public static void main(String[] args) {
    //匿名内部类
    Runnable runnable=new Runnable() {
      
      @Override
      public void run() {
        System.out.println("子线程执行了.........");
      }
    };
    
    //Lambda表达式
    Runnable runnable2=()->System.out.println("子线程执行了2.........");
    
    new Thread(runnable2).start();
    new Thread(()->System.out.println("子线程执行了3.........")).start();
    
    /
    //匿名内部类
    Comparator<String> com=new Comparator<String>() {

      @Override
      public int compare(String o1, String o2) {
        // TODO Auto-generated method stub
        return o1.length()-o2.length();
      }
    };
    
    //Lambda表达式
    
    Comparator<String> com2=(String o1, String o2)-> {
      // TODO Auto-generated method stub
      return o1.length()-o2.length();
    };
    
    Comparator<String> com3=(o1,o2)->o1.length()-o2.length();
    
    TreeSet<String> treeSet=new TreeSet<>(com3);
  }
}

Lambda引入了新的操作符:->(箭头操作符),->将表达式分成两部分:

  • 左侧:(参数1,参数2…)表示参数列表
  • 右侧:{ }内部是方法体

注意事项:

19.2.4 案例展示

Usb接口:

@FunctionalInterface
public interface Usb {
  void service();
}

TestUsb类:

public class TestUsb {
  public static void main(String[] args) {
    //匿名内部类
    Usb mouse=new Usb() {
      
      @Override
      public void service() {
        System.out.println("鼠标开始工作了..........");
      }
    };
    
    Usb fan=()->System.out.println("风扇开始工作了..........");
    
    
    run(mouse);
    run(fan);
  }
  public static void run(Usb usb) {
    usb.service();
  }
}

19.3 函数式接口


19.3.1 概念 如果一个接口只有一个抽象方法,则该接口称之为函数式接口。

函数式接口可以使用Lambda表达式,Lambda表达式会被匹配到这个抽象方法上 。

@FunctionalInterface 注解检测接口是否符合函数式接口规范。

19.3.2 常见函数式接口

接口 参数类型 返回类型 说明
Consumer< T > 消费型接口 T void void accept(T t);对类型为T的对象应用操作
Supplier< T > 供给型接口 T T get(); 返回类型为T的对象
Function< T,R > 函数型接口 T R R apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。
Predicate< T > 断言型接口 T boolean boolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。

案例演示:

public class TestFun {
  public static void main(String[] args) {

    //Lambda表达式
    Consumer<Double> consumer= t->System.out.println("聚餐消费:"+t);
    
    happy(t->System.out.println("聚餐消费:"+t), 1000);
    happy(t->System.out.println("唱歌消费:"+t), 2000);
    
    int[] arr=getNums(()->new Random().nextInt(100), 5);
    System.out.println(Arrays.toString(arr));
    int[] arr2=getNums(()->new Random().nextInt(1000), 10);
    System.out.println(Arrays.toString(arr2));
    
    String result=handlerString(s->s.toUpperCase(), "hello");
    System.out.println(result);
    String result2=handlerString(s->s.trim(), "   zhangsan        ");
    System.out.println(result2);
    
    List<String> list=new ArrayList<>();
    list.add("zhangsan");
    list.add("zhangwuji");
    list.add("lisi");
    list.add("wangwu");
    list.add("zhaoliu");
    List<String> result=filterNames(s->s.startsWith("zhang"), list);
    System.out.println(result.toString());
    
    List<String> result2=filterNames(s->s.length()>5, list);
    System.out.println(result2);
  }
  //Consumer 消费型接口
  public static void happy(Consumer<Double> consumer,double money) {
    consumer.accept(money);
  }
  
  //Supplier 供给型接口
  public static int[] getNums(Supplier<Integer> supplier,int count) {
    int[] arr=new int[count];
    for(int i=0;i<count;i++) {
      arr[i]=supplier.get();
    }
    return arr;
  }
  
  //Function函数型接口
  public static String handlerString(Function<String, String> function,String str) {
    return function.apply(str);
  }
  
  //Predicate 断言型接口
  
  public static List<String> filterNames(Predicate<String> predicate,List<String> list){
    List<String> resultList=new ArrayList<String>();
    for (String string : list) {
      if(predicate.test(string)) {
        resultList.add(string);
      }
    }
    return resultList;
  }
  
}

19.4 方法引用


19.4.1 概念

  • 方法引用是Lambda表达式的一种简写形式。
  • 如果Lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用。

常见形式:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new

19.4.2 基本使用

Employee类:

publpublic class Employee {
  private String name;
  private double money;
  public Employee() {
    // TODO Auto-generated constructor stub
  }
  
  public Employee(String name, double money) {
    super();
    this.name = name;
    this.money = money;
  }

  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public double getMoney() {
    return money;
  }
  public void setMoney(double money) {
    this.money = money;
  }
  @Override
  public String toString() {
    return "Employee [name=" + name + ", money=" + money + "]";
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(money);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Employee other = (Employee) obj;
    if (Double.doubleToLongBits(money) != Double.doubleToLongBits(other.money))
      return false;
    if (name == null) {
      if (other.name != null)
        return false;
    } else if (!name.equals(other.name))
      return false;
    return true;
  }
  
}

TestEmployee类:

public class Demo4 {
  public static void main(String[] args) {
    //1 对象::实例方法
    Consumer<String> consumer=s->System.out.println(s);
    consumer.accept("hello");
    Consumer<String> consumer2=System.out::println;
    consumer.accept("world");
    
    //2类::静态方法
    Comparator<Integer> com=(o1,o2)->Integer.compare(o1, o2);
    Comparator<Integer> com2=Integer::compare;
      
    //3类::实例方法
    Function<Employee, String> function=e->e.getName();
    Function<Employee, String> function2=Employee::getName;
    
    System.out.println(function2.apply(new Employee("小明", 50000)));
    
    //4类::new
    Supplier<Employee> supplier=()->new Employee();
    Supplier<Employee> supplier2=Employee::new;
    
    Employee employee=supplier.get();
    System.out.println(employee.toString());
    
  }
}

19.5 Stream


19.5.1 概念

流(Stream)与集合类似,但集合中保存的是数据,而Stream中保存对集合或数组数据的操作。

19.5.2 Stream特点

  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的,会等到需要结果的时候才执行。

19.5.3 Stream使用步骤

创建:

  • 新建一个流。

中间操作:

  • 在一个或多个步骤中,将初始Stream转化到另一个Stream的中间操作。

终止操作:

  • 使用一个终止操作来产生一个结果。该操作会强制之前的延迟操作立即执行,在此之后,该Stream就不能使用了。

19.5.4 创建Stream

  • 通过Collection对象的stream()或parallelStream()方法。
  • 通过Arrays类的stream()方法。
  • 通过Stream接口的of()、iterate()、generate()方法。
  • 通过IntStream、LongStream、DoubleStream接口中的of、range、rangeClosed方法。

案例演示:

public class Demo5 {
  public static void main(String[] args) {
    //(1)Collection对象中的stream()和parallelStream()方法
    ArrayList<String> arrayList=new ArrayList<>();
    arrayList.add("apple");
    arrayList.add("huawei");
    arrayList.add("xiaomi");
    Stream<String> stream = arrayList.parallelStream();
    //遍历
//    stream.forEach(s->System.out.println(s));
    stream.forEach(System.out::println);
    //(2)Arrays工具类的stream方法
    String[] arr= {"aaa","bbb","ccc"};
    Stream<String> stream2=Arrays.stream(arr);
    stream2.forEach(System.out::println);
    
    //(3)Stream接口中的of iterate 、generate 方法
    
    Stream<Integer> stream3 = Stream.of(10,20,30,40,50);
    stream3.forEach(System.out::println);
    //迭代流
    System.out.println("-----迭代流------");
    Stream<Integer> iterate = Stream.iterate(0, x->x+2);
    iterate.limit(5).forEach(System.out::println);
    System.out.println("--------生成流----------");
    //生成流
    Stream<Integer> generate = Stream.generate(()->new Random().nextInt(100));
    generate.limit(10).forEach(System.out::println);
    
    //(4)IntStream,LongStream,DoubleStream  的of  、range、rangeClosed
    IntStream stream4 = IntStream.of(100,200,300);
    stream4.forEach(System.out::println);
    IntStream range = IntStream.rangeClosed(0, 50);
    range.forEach(System.out::println);
  }
}

19.5.5 中间操作

常见中间操作:

  • filter、limit、skip、distinct、sorted
  • map
  • parallel

案例演示:

public class Demo6 {
  public static void main(String[] args) {
    ArrayList<Employee> list=new ArrayList<>();
    list.add(new Employee("小王", 15000));
    list.add(new Employee("小张", 12000));
    list.add(new Employee("小李", 18000));
    list.add(new Employee("小孙", 20000));
    list.add(new Employee("小刘", 25000));
    //list.add(new Employee("小刘", 25000));
    //中间操作1 
        //filter过滤、limit 限制、skip 跳过、distinct 去掉重复、sorted排序
    //(1) filter过滤
    System.out.println("------filter-------");
    list.stream()
      .filter(e->e.getMoney()>15000)
      .forEach(System.out::println);
    //(2) limit限制
    System.out.println("----limit------");
    list.stream()
      .limit(2)
      .forEach(System.out::println);
    //(3) skip跳过
    System.out.println("-----skip------");
    list.stream()
      .skip(2)
      .forEach(System.out::println);
    System.out.println("------distinct--------");
    //(4) distinct去重复
    list.stream()
      .distinct()
      .forEach(System.out::println);
    
    System.out.println("---------sorted---------");
    //(5) sorted排序
    list.stream()
      .sorted((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()))
      .forEach(System.out::println);
        
    //中间操作2 map
    System.out.println("---------map--------");
    list.stream()
      .map(e->e.getName())
      .forEach(System.out::println);
    //中间操作3 parallel 采用多线程 效率高
    System.out.println("---------map--------");
    list.parallelStream()
      .forEach(System.out::println);
  }
}

串行流和并行流:

  • 串行流使用单线程。
  • 并行流使用多线程,效率更高。
public class Demo7 {
  public static void main(String[] args) {
    //串行流和并行流的区别
    ArrayList<String> list=new ArrayList<>();
    for(int i=0;i<5000000;i++) {
      list.add(UUID.randomUUID().toString());
    }
    //串行:10秒  并行:7秒
    long start=System.currentTimeMillis();
        long count=list.Stream().sorted().count();
    //long count=list.parallelStream().sorted().count();
    System.out.println(count);
    long end=System.currentTimeMillis();
    System.out.println("用时:"+(end-start));
  }
}

19.5.6 终止操作

常见终止操作:

  • forEach、min、max、count
  • reduce、collect

案例演示:

public class Demo8 {
  public static void main(String[] args) {
    ArrayList<Employee> list = new ArrayList<>();
    list.add(new Employee("小王", 15000));
    list.add(new Employee("小张", 12000));
    list.add(new Employee("小李", 18000));
    list.add(new Employee("小孙", 20000));
    list.add(new Employee("小刘", 25000));
    //1 终止操作 foreach
    list.stream()
      .filter(e->{
          System.out.println("过滤了....");
          return e.getMoney()>15000;
        })
      .forEach(System.out::println);
    //2 终止操作 min max count
    System.out.println("-----min-----");
    Optional<Employee> min = list.stream()
      .min((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
    System.out.println(min.get());
    System.out.println("-----max-----");
    Optional<Employee> max = list.stream()
      .max((e1,e2)->Double.compare(e1.getMoney(), e2.getMoney()));
    System.out.println(max.get());
    
    long count = list.stream().count();
    System.out.println("员工个数:"+count);
    
    //3 终止操作 reduce 规约
    //计算所有员工的工资和
    System.out.println("--------reduce---------");
    Optional<Double> sum = list.stream()
      .map(e->e.getMoney())
      .reduce((x,y)->x+y);
    System.out.println(sum.get());
    
    //4 终止方法 collect收集
    //获取所有的员工姓名,封装成一个list集合
    System.out.println("------collect------");
    List<String> names = list.stream()
      .map(e->e.getName())
      .collect(Collectors.toList());
    for (String string : names) {
      System.out.println(string);
    }
  }
}

19.6 新时间API


19.6.1 概述

之前时间API存在问题:线程安全问题、设计混乱。

本地化日期时间 API:

  • LocalDate
  • LocalTime
  • LocalDateTime

Instant:时间戳。

ZoneId:时区。

Date、Instant、LocalDateTime的转换。

DateTimeFormatter:格式化类。

19.6.2 LocalDateTime类

表示本地日期时间,没有时区信息

public class Demo2 {
  public static void main(String[] args) {
    //1创建本地时间
    LocalDateTime localDateTime=LocalDateTime.now();
    //LocalDateTime localDateTime2=LocalDateTime.of(year, month, dayOfMonth, hour, minute)
    System.out.println(localDateTime);
    System.out.println(localDateTime.getYear());
    System.out.println(localDateTime.getMonthValue());
    System.out.println(localDateTime.getDayOfMonth());
    
    //2添加两天
    LocalDateTime localDateTime2 = localDateTime.plusDays(2);
    System.out.println(localDateTime2);
    
    //3减少一个月
    LocalDateTime localDateTime3 = localDateTime.minusMonths(1);
    System.out.println(localDateTime3);
  }
}

19.6.3 Instant、ZoneId类

Instant表示瞬间;和前面Date类似。

ZoneId表示时区信息。

public class Demo3 {
  public static void main(String[] args) {
    //1 创建Instant:时间戳
    Instant instant=Instant.now();
    System.out.println(instant.toString());
    System.out.println(instant.toEpochMilli());
    System.out.println(System.currentTimeMillis());
    //2 添加减少时间
    
    Instant instant2 = instant.plusSeconds(10);
    
    System.out.println(Duration.between(instant, instant2).toMillis());
    
    //3ZoneId
    Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
    for (String string : availableZoneIds) {
      System.out.println(string);
    }
    
    System.out.println(ZoneId.systemDefault().toString());
    
    //1 Date --->Instant--->LocalDateTime
    System.out.println("-------------Date --->Instant---->LocalDateTime-----------");
    Date date=new Date();
    Instant instant3 = date.toInstant();
    System.out.println(instant3);
    
    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant3, ZoneId.systemDefault());
    System.out.println(localDateTime);
    
    //2 LocalDateTime --->Instant--->Date
    System.out.println("-------------LocalDateTime --->Instant---->Date-----------");
  
    Instant instant4 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
    System.out.println(instant4);
    Date from = Date.from(instant4);
    System.out.println(from);
    
  }
}

19.6.4 DateTimeFormatter类

DateTimeFormatter是时间格式化类。

public class Demo4 {
  public static void main(String[] args) {
    //创建DateTimeFormatter
    DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
    //1 把时间格式化成字符串
    String format = dtf.format(LocalDateTime.now());
    System.out.println(format);
    //2 把字符串解析成时间
    LocalDateTime localDateTime = LocalDateTime.parse("2020/03/10 10:20:35", dtf);
    System.out.println(localDateTime);
  }
}

stant instant4 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
    System.out.println(instant4);
    Date from = Date.from(instant4);
    System.out.println(from);
    
  }
}

19.6.4 DateTimeFormatter类

DateTimeFormatter是时间格式化类。

public class Demo4 {
  public static void main(String[] args) {
    //创建DateTimeFormatter
    DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
    //1 把时间格式化成字符串
    String format = dtf.format(LocalDateTime.now());
    System.out.println(format);
    //2 把字符串解析成时间
    LocalDateTime localDateTime = LocalDateTime.parse("2020/03/10 10:20:35", dtf);
    System.out.println(localDateTime);
  }
}


目录
相关文章
|
3天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
14 2
|
5天前
|
Java
探索Java中的Lambda表达式
【10月更文挑战第37天】本文将带你深入理解Java的Lambda表达式,从基础语法到高级特性,通过实例讲解其在函数式编程中的应用。我们还将探讨Lambda表达式如何简化代码、提高开发效率,并讨论其在实际项目中的应用。
|
8天前
|
Java API
Java中的Lambda表达式与函数式编程####
【10月更文挑战第29天】 本文将深入探讨Java中Lambda表达式的实现及其在函数式编程中的应用。通过对比传统方法,我们将揭示Lambda如何简化代码、提高可读性和维护性。文章还将展示一些实际案例,帮助读者更好地理解和应用Lambda表达式。 ####
|
12天前
|
Java API 开发者
Java中的Lambda表达式与函数式编程####
在Java的演变过程中,Lambda表达式和函数式编程的引入无疑是一次重大的飞跃。本文将深入探讨Lambda表达式的定义、用法及优势,并结合实例说明如何在Java中利用Lambda表达式进行函数式编程。通过对比传统编程方式,揭示Lambda表达式如何简化代码、提高开发效率和可维护性。 ####
|
16天前
|
供应链 数据挖掘 API
电商API接口介绍——sku接口概述
商品SKU(Stock Keeping Unit)接口是电商API接口中的一种,专门用于获取商品的SKU信息。SKU是库存量单位,用于区分同一商品的不同规格、颜色、尺寸等属性。通过商品SKU接口,开发者可以获取商品的SKU列表、SKU属性、库存数量等详细信息。
|
18天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
8天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
17天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
4天前
|
安全 Java 开发者
深入解读JAVA多线程:wait()、notify()、notifyAll()的奥秘
在Java多线程编程中,`wait()`、`notify()`和`notifyAll()`方法是实现线程间通信和同步的关键机制。这些方法定义在`java.lang.Object`类中,每个Java对象都可以作为线程间通信的媒介。本文将详细解析这三个方法的使用方法和最佳实践,帮助开发者更高效地进行多线程编程。 示例代码展示了如何在同步方法中使用这些方法,确保线程安全和高效的通信。
22 9
|
7天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####