JDK8以上提高开发效率

1 接口的默认方法和静态方法

1.1 接口中可以定义默认方法和静态方法。

  • 默认方法使用default修饰,静态方法和默认方法可以多个;
  • 静态方法通过接口直接调用,默认方法通过接口实现类调用
  • 默认方法可以重写
public interface InterfaceTest {
  
    default String defaultMethod(){
        return "InterfaceTest  defaultMethod";
    }
    static String staticMethod(){
        return "InterfaceTest  staticMethod";
    }
}

public class InterfaceMain {
    public static void main(String[] args) {
  
        //接口中的默认方法必须通过接口实现类调用
        InterfaceTestImpl impl = new InterfaceTestImpl();
        System.out.println(impl.defaultMethod());
  
        // 接口中的静态方法可以直接通过接口调用
        System.out.println(InterfaceTest.staticMethod());
    }
}

接口中默认方法可以重写

1.2 如果子类继承父类和实现接口中方法重名,采用类优先原则 调用父类方法

public class Inter {
    public String defaultMethod(){
        return "Inter defaultMethod";
    }
}

public interface InterfaceTest {

    default String defaultMethod(){
        return "InterfaceTest  defaultMethod";
    }
}

public class InterfaceMain extends Inter implements InterfaceTest{
    public static void main(String[] args) {
        InterfaceMain i =  new InterfaceMain();
        System.out.println(i.defaultMethod());
    }
}

输入结果:Inter defaultMethod

2 Lambda表达式

2.1 Lambda基础格式

(参数列表)->{
  方法体
}
  1. 没有参数的Lambda表达式,方法体只有一个可以省略return
    ()-> new Student();
  2. 只有一个参数的Lambda表达式
x->{
	System.out.prontle(x);
	return x;
}
  1. 有多个参数的Lambda表达式
(int x,int y)->{
	System.out.prontle(x);
	System.out.prontle(y);
	return x+y;
}

上述写法可以简化,参数列表中的参数的数据类型JVM可以根据上下文进行推断,所以可以不定义类型

(x,y)->{
	System.out.prontle(x);
	System.out.prontle(y);
	return x+y;
}
  1. 一个参数和仅一条语句的Lambda表达式
    x -> 3+x;
  2. 多个参数和鲸一条语句的Lambda表达式
    (x+y)->x+y;

2.2 Lambda使用案例

  1. Lambda简化匿名内部类写法
Runnable runnable1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("hello Lambda");
    }
 };

//Lambda简化匿名内部类写法
Runnable runnable2 = ()-> System.out.println("hello Lambda");
2. Lambda对数组排序

String[] arr = new String[]{"c","b","a"};

//原写法
Arrays.sort(arr, new Comparator<String>() {
  @Override
  public int compare(String o1, String o2) {
     return o1.compareTo(o2);
  }
});
//Lambda简化写法1
Arrays.sort(arr,(o1,o2)->(o1.compareTo(o2)));
//Lambda简化写法2,再次简化
Arrays.sort(arr, String::compareTo);

3 函数式接口

Java8为了让现有的函数更加友好的使用Lambda表达式,引入了函数式接口。函数式接口仅有一个抽象方法,如果声明多个抽象方法则会报错,但默认方法和静态方法在此接口中可以有多个。

3.1 函数式接口声明和使用

自定义函数接口需要在接口上加@FunctionalInterface

//函数式接口定义
@FunctionalInterface
public interface MyInterface {
    void excute();
}

//函数式接口调用
public static void demo(MyInterface myInterface) {
  myInterface.excute();
}

public static void main(String[] args) {
  demo(() -> System.out.println("函数式接口调用"));
}

3.2 常见应用

​ 在Java8类库设计中,已经引入了几个函数式接口:Predicate、Consumer、Function、Supplier

3.2.1 Predicate

​ Predicate属于java.util.function包下,用于进行判断操作,内部顶一个抽象方法test、三个默认方法and、negate、or、一个静态方法isEqual。

3.2.2 Consumer

​ Comsumer,用于==获取数据的操作==。内部定义了一个抽象方法accept,一个默认方法andThen。

3.2.3 Function

​ Function主要用于==进行类型转换的操作==。内部提供一个抽象方法apply、两个默认方法compose、andThen、一个静态方法identity。

3.2.4 Supplier

​ Supplier也是用来==获取值操作==,内部只有一个抽象方法get。与Consumer 的 accept方法不同于 Consumer 的 accept没有返回值,supplier中的get方法有返回值。

4 类型检查&推断

​ 自动类型推断:在Java8中可以省略Lambda表达式的所有参数类型,在编译的时根据Lambda表达式的上下文信息推断出参数的正确类型,这就是所谓的类型推断。

5 方法引用

​ 方法引用更进一步的优化了Lambda的使用。它让代码感觉更加的自然。我们可以直接使用::来简化Lambda表达式的使用。其语法如下:类名或实例名::属性

List<Student> students = new ArrayList<>();
students.add(new Student(2,"张三","N"));
students.add(new Student(1,"李四","V"));
students.add(new Student(3,"万维","V"));

students.sort(Comparator.comparing(Student::getId));

6 Stream流

​ Stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或IO等。在stream中的操作每一次都会产生新的流,内部不会像普通集合操作一样立刻获取值,而是惰性取值,只有等到用户真正需要结果的时候才会执行。
**案例1:**获取年龄小于20岁学生,并且年龄从小到大排序,只取姓名

List<Student> students = new ArrayList();

@BeforeEach
public void init(){
  students.add(new Student(1,"张三","N",19));
  students.add(new Student(2,"赵六","N",17));
  students.add(new Student(4,"王五","V",22));
  students.add(new Student(3,"李四","V",23));
}

/**
     * 获取年龄小于20岁学生,并且年龄从小到大排序,只取姓名
     * 期望:赵六 张三
     */
@Test
public void filter20AndSort(){
  List<String> list = students.stream()
    .filter(s -> s.getAge() < 20) //获取年龄小于20岁学生
    .sorted(Comparator.comparing(Student::getAge)) //按年龄排序
    .map(Student::getName)//取姓名
    .collect(Collectors.toList()); //收集成list
  System.out.println(list);
}

6.1 流操作详解

6.1.1 筛选

  1. filter( ) 筛选符合条件的数据
    获取及格学生名单
List<Student> students = new ArrayList();

@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",17,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}

/**
* 获取及格学生名单
*/
@Test
public void filterIspass(){
    List<Student> passStudents = students.stream()
    .filter(Student::isIspass)
    .collect(Collectors.toList());
    System.out.println(passStudents);
}
  1. distinct( )去重
    ​ 底层通过LinkHashSize实现。注意:对象去重需重写equals和hashcode方法
@Test
public void distinct(){
    List<Integer> list = Arrays.asList(1,2,3,2,6,1,4,5);
    List<Integer> result = list.stream().distinct().collect(Collectors.toList());
    System.out.println(result);
}

6.1.2 切片

  1. limit ( ) 返回一个不超过给定长度的流。从前往后
@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",17,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}
//取第一条数据
@Test
public void limt(){
    List<Student> result = students.stream().limit(1).collect(Collectors.toList());
    System.out.println(result);
}
  1. skip( ) 跳过给定数量 取剩余的数据
@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",17,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}
@Test
public void skip(){
		//取最后一条数据
    List<Student> result = students.stream().skip(3).collect(Collectors.toList());
    System.out.println(result);
}

skip与limit结合使用
​ 跳过前2条取1条数据

@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",17,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
    students.add(new Student(3,"韩七","V",25,false));
}
@Test
public void limtAndSkip(){
    List<Student> result = students.stream().skip(2).limit(1).collect(Collectors.toList());
    System.out.println(result);
}

6.1.3 映射

​ 在对集合进行操作的时候,我们经常会从某些对象中选择性的提取某些元素的值。可以使用map( )进行映射

@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",17,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}
@Test
public void map(){
    List<String> result = students.stream()
    .map(Student::getName) //只取集合中的姓名值
    .collect(Collectors.toList());
    System.out.println(result);
}

案例:将集合类型转换并求和

@Test
public void map2(){
    List<String> list = Arrays.asList("1","2","3","2","6");
    int result = list.stream()
            .mapToInt(s->Integer.parseInt(s))//类型转换
            .sum(); //求和
    System.out.println(result);
}

6.1.4 匹配

​ 用于判断集合中某些元素是否匹配对应的条件,如果有的话,再进行后续的操作。如anyMatch、allMatch等,对应&& 和|| ||运算符。

  1. anyMatch( ) 只要有1条数据满足条件即返回TRUE 否则返回FALSE
@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",22,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}

@Test
public void anyMath(){
    if(students.stream().anyMatch(s->s.getAge()==22)){
        System.out.println("集合中有22岁的学生");
    }
}
  1. allMatch( ) 当所有数据满足条件后返回TRUE 否则返回FALSE。
@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",22,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}

@Test
public void allMath(){
    if(students.stream().allMatch(Student::isIspass)){
        System.out.println("所有学生及格");
    }else{
        System.out.println("还有学生不及格");
    }
}

6.1.5 查找

  1. findAny( ) 随机查找符合条件的数据,找到返回该数据(并行流情况下才会随机返回)
@BeforeEach
public void init(){
    students.add(new Student(1,"张三","N",19,false));
    students.add(new Student(2,"赵六","N",22,true));
    students.add(new Student(4,"王五","V",22,true));
    students.add(new Student(3,"李四","V",23,false));
}
@Test
public void findAny(){
    Optional<Student> optional = students.stream().filter(s -> s.getAge() > 10).findAny();
    if(optional.isPresent()){
        Student student = optional.get();
        System.out.println(student);
    }
}
  1. findFirst( ) 返回第一个符合条件的数据

6.1.6 聚合

  1. reduce()累加。参数一表示初始值*(累加后会再次加上初始的值)*。
public void reduce(){
    List<Integer> list = Arrays.asList(1,2,3,4,5);
//        Integer sum = list.stream().reduce(0, (a, b) -> a + b);
//        Integer sum = list.stream().reduce(0, Integer::sum);
    System.out.println(sum);
    
    Optional<Integer> optional = list.stream().reduce(Integer::sum);
    if(optional.isPresent()){
        System.out.println(optional.get());
    }
}
  1. max( ) 取出数据中最大的值
@Test
public void max(){
    List<Integer> list = Arrays.asList(1,2,3,4,5);
//        Optional<Integer> optional = list.stream().reduce(Integer::max);
    Optional<Integer> optional = list.stream().max(Integer::compareTo);
    if(optional.isPresent()){
        System.out.println(optional.get());
    }
}
  1. min( )最小值。使用同max

6.1.7 构建流

  1. 基于数组创建
    public void create(){
    //1.通过of方法创建
    Stream stream = Stream.of(1, 2, 3);
    //2.通过数组stream方法创建,底层实现相同
    IntStream stream1 = Arrays.stream(new int[]{1, 2, 3});
    }
  2. 基于文件创建

6.1.8 收集器

  1. collect( ) 可以收集流中的数据到集合或者数组中
public void collect(){
    //1.通过of方法创建
    Stream<Integer> stream = Stream.of(1, 2, 3);
    List<Integer> list = stream.collect(Collectors.toList());
}
  1. 分组/分区/拼接
    分组:groupingBy( )
    通过Collectors.groupingBy( )完成。分组可以分多个
@BeforeEach
public void init() {
    students.add(new Student(1, "张三", "N", 19, false));
    students.add(new Student(2, "赵六", "N", 22, true));
    students.add(new Student(4, "王五", "V", 22, true));
    students.add(new Student(3, "李四", "V", 23, false));
}

@Test
public void groupingBy() {
    //按性别分组
    Map<String, List<Student>> map = students.stream()
            .collect(Collectors.groupingBy(Student::getSex));
}

分区:partitioningBy( )
​ 分组通过Collectors.partitioningBy( )完成。分区只能分2个。根据返回值是否为TRUE,把集合分为2个列表,一个TRUE列表,一个FALSE列表。

@BeforeEach
public void init() {
    students.add(new Student(1, "张三", "N", 19, false));
    students.add(new Student(2, "赵六", "N", 22, true));
    students.add(new Student(4, "王五", "V", 22, true));
    students.add(new Student(3, "李四", "V", 23, false));
}
@Test
public void partitioningBy() {
    Map<Boolean, List<Student>> map = students.stream()
            .collect(Collectors.partitioningBy(s -> s.getSex().endsWith("N")));
    System.out.println(map);
    //{
    // false=[Student(id=4, name=王五, sex=V, age=22, ispass=true), Student(id=3, name=李四, sex=V, age=23, ispass=false)], 
    // true=[Student(id=1, name=张三, sex=N, age=19, ispass=false), Student(id=2, name=赵六, sex=N, age=22, ispass=true)]
    // }
}

拼接:joining( )
Collectors.joining() 会根据指定的连接符,将所有元素连接成一个字符串。

@BeforeEach
    public void init() {
        students.add(new Student(1, "张三", "N", 19, false));
        students.add(new Student(2, "赵六", "N", 22, true));
        students.add(new Student(4, "王五", "V", 22, true));
        students.add(new Student(3, "李四", "V", 23, false));
    }
    @Test
    public void joining() {
        String names = students.stream()
                .map(Student::getName)
                .collect(Collectors.joining());
        System.out.println(names);//张三赵六王五李四
    }

6.2 数据并行化

​ parallelStream( )替换stream( )

6.2.1 并行和并发

​并行:多个任务在同一时间点发生,并由不同的CPU进行处理,互相不抢占资源。

并发:多个任务在同一时间内同时发生,但由同一个CPU处理,互相抢夺资源。

6.2.2 并行流原理介绍

​ 对于并行流,其在底层中,是沿用Java7提供的fork\join分解合并框架进行实现。fork根据==CPU可用核数==进行数据分块,join对各个fork进行合并,实现过程如下图。
​ 假如现在的操作是运行一台4核机器上

7 异步编程CompleTableFuture

​ completableFuture是Java1.8提供的一个新类,其实现了Future与completionStage两个接口。提供了诸多API扩展功能,可以通过stream形式简化异步编程的复杂度,同时提供通过回调方式处理计算结果

7.1 创建异步任务

​ 在completableFuture中提供了四个静态方法用于创建异步任务:

runAsync(Runnable runnable) //不带返回值,默认使用守护进程线程池,不推荐
runAsync(Runnable runnable,Executor executor)//无返回值,自定义线程池
supplyAsync(Supplier<U> supplier)//有返回值,默认使用守护进程线程池,不推荐
supplyAsync(Supplier<U> supplier,Executor executor)//有回值,自定义线程池
posted @ 2022-02-26 03:02  Dvomu  阅读(68)  评论(0编辑  收藏  举报