Java8新特性

Java8新特性

  • 一、Stream流
    • 1. Stream简介
    • 2. Stream用法
      • 2. 1获取流
      • 2.2 流操作
        • 中间操作
        • 终端操作
      • Map 的 Stream用法 示例
  • 二、Lambda表达式
    • 1.背景
    • 2.简介
    • 3.Lambda表达式的结构
    • 4.Lambda表达式 示例
  • 三、函数式接口(Functional Interface)
  • 四、Optional类--解决空指针问题
  • 五、方法引用
    • 对象::实例方法名
    • 类::静态方法名
    • 类::实例方法名
  • 六、构造器引用、数组引用
  • 七、接口中静态方法和默认方法
    • 静态方法
    • 默认方法
    • 默认方法的继承问题

一、Stream流

1. Stream简介

Stream允许我们以声明式的方式处理数据集合,可以将Stream看作是遍历数据集合的高级迭代器。Stream 与Lambda表达式结合使用,将使编码效率大大提高,可读性增强。

注意:Stream与IO中的InputStream/OutputStream是不同的概念

操作案例:Java8新特性_第1张图片使用stream将集合中的手机按照序号num从小到大排序:
Java8新特性_第2张图片
结果:
Java8新特性_第3张图片
Stream流的操作顺序

在这里插入图片描述
Stream语法

| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|

2. Stream用法

2. 1获取流

  1. Collection接口下的stream()获取流

Java8新特性_第4张图片

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
  1. 使用 Arrays 中的 stream() 方法,将数组转成流

在这里插入图片描述

Integer[] arr= new Integer[10]; 
Stream<Integer> stream = Arrays.stream(arr);
  1. 使用 Stream 中的静态方法:of()

Java8新特性_第5张图片

Stream<Integer> stream = Stream.of(4,3,2,7,5,1,6);
  1. 使用 BufferedReader.lines() 方法,将每行内容转成流

在这里插入图片描述

BufferedReader reader=new BufferedReader(new FileReader("test.txt")); 
Stream<String> lineStream = reader.lines();

2.2 流操作

流操作可以分为中间操作终端操作

List<Apple> apples = 
			applestore .stream() 获得流
			 		   .filter(a -> a.getColor().equals("红色")) 中间操作
			 		   .collect(Collectors.toList()); 终端操作

简单来说Stream的流程就是
数据源->中间操作->终端操作->结果

中间操作

  • filter():过滤流中的某些元素
  • sorted():自然排序,流中元素需实现Comparable接口
  • distinct():去除重复元素
  • limit(n):获取n个元素
  • skip(n):跳过n个元素,配合limit(n)可实现分页
  • map():将其映射为一个新的元素
    Java8新特性_第6张图片
    Java8新特性_第7张图片
    map():
  1. 对集合中的每一个元素求平方
    Java8新特性_第8张图片
    在这里插入图片描述
    2.使用map()将String型的整数转为Integer型的整数
    Java8新特性_第9张图片
    在这里插入图片描述

终端操作

  • forEach():遍历流中的元素
  • toArray():将流中的元素倒入一个数组中
  • Min():返回流中元素的最小值
  • Max():返回流中元素的最大值
  • count():返回流中元素的总个数
  • reduce():所有元素求和
  • anyMatch():接收一个Predicate函数,只要流中有一个元素满足条件则返回true,否则返回false
  • allMatch():接收一个Predicate函数,当流中所有元素都符合条件时才返回true,否则返回false
  • findFirst():返回流中的第一个元素
  • collect():将流中的元素倒入一个集合(Collection/Map)
/**
         * 终端操作 -- 结果
         */
        Integer[] arr = new Integer[]{3,1,5,7,2,6,4,4,0};
        Object[] arr1 =  Arrays.stream(arr)
                .distinct()
                .sorted()
                .toArray();        //toArray()将流中元素倒入Object数组中
        //forEach()
        Arrays.stream(arr1).forEach(e-> System.out.print(e+" "));
        //count 统计
        Long count = Arrays.stream(arr).count();
        System.out.println(count);
        //anyMatch 流中任意一个元素符合条件时返回true
        boolean any = Arrays.stream(arr).anyMatch((e)->{return e>3;});
        System.out.println("有1个元素>3 :"+any);
        //anyMatch 流中所有元素符合条件时返回true
        boolean all = Arrays.stream(arr).allMatch((e)->{return e>3;});
        System.out.println("所有元素>3 :"+all);
        //findFirst 返回流中第一个元素
        System.out.println("流中第一个元素 :"+Arrays.stream(arr).findFirst());
        //reduce:所有元素求和
        Optional<Integer> res = Arrays.stream(arr).reduce((a, b)->a+b);
        System.out.println("元素求和 :"+res);

Java8新特性_第10张图片

Map 的 Stream用法 示例

根据对象ID属性将java集合拆分为子集合

Map<Integer, List<LotRealTimeProductionInfo>> retByIdMap =
                lotRetInfoList.stream().collect(Collectors.groupingBy(LotRealTimeProductionInfo::getLotId));

二、Lambda表达式

Lambda表达式是Java8增加的语言级的新特性。

1.背景

在Java中,一切皆对象, 数组、类的实例都是对象。

在Java中定义函数或者方法不可能完全独立,也不能将方法作为参数或返回一个方法给实例。

在Java8之前,要实现将某些功能传递给某个方法,要写匿名内部类:

		String[] arr = {"c","a","d","b"};
        //Arrays.sort(arr,new StringSort());// 外部类
        //Arrays.sort(arr,new InnerStringSort());// 内部类
        //new + 接口/抽象类 创建匿名内部类对象
        Arrays.sort(arr, new Comparator<String>() {
        	@Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1);
            }
        });
        System.out.println(Arrays.toString(arr));

在这里插入图片描述

为了对集合进行排序,为Comparator接口创建了一个匿名内部类对象,重写了接口中的方法来实现排序的功能。

2.简介

Lambda表达式是一个匿名函数,可以将Lambda表达式理解为一段可以传递的代码(将代码段数据一样传递)。使用Lambda表达式可以写出更简洁,更灵活的代码。

Lambda表达式的本质只是一个语法糖,有编译器推断并帮助我们转换包装为常规的代码,因此我们可以使用更少的代码来实现相同的功能。

Java中的Lambda表达式通常使用(argument)->{body}的语法书写:

	->的左侧:Lambda表达式的参数列表
	->的右侧:Lambda表达式中需要执行的功能,及Lambda(参数1,参数2,...)->{函数体}
	(类 类实例,类 类实例,...)->{函数体}

下面是一些Lambda表达式的例子:

  • 无参数,无返回值,lambda 体中只有一行代码时,{}可以忽略
    () -> System.out.println("Hello World");
  • 无参数,有返回值
    () -> { return 3.1415 };
  • 有参数,无返回值
    (String s) -> { System.out.println(s); }
  • 有一个参数,无返回值
    s -> { System.out.println(s); }
  • 有多个参数,有返回值
    (int a, int b) -> { return a + b; }
  • 有多个参数,表达式参数类型可以不写,jvm 可以根据上下文进行类型推断
    (a, b) -> { return a - b; }

3.Lambda表达式的结构

  • Lambda表达式参数可以有0个、1个或多个正文语句可以有0条,1条或多条
  • 可以显式声明参数类型,也可以由编译器自动从上下位推断参数的类型。
    (int a,int b)与 (a,b)相同
  • 空括号表示无参 ()->100
  • 正文只有一条语句,大括号不用写,且表达式返回值类型与匿名函数的返回类型相同。(a,b)->return a+b;
  • 只有一个参数时,如果不指明类型,那么可以不写括号x->return x*x;
package com.ffyc.forword.lambd;

import java.util.Arrays;

public class LambdDemo {
    /*
        lambda 语法
            (参数列表)->{函数体}
        是匿名函数,一般在方法的参数为"接口"时,代替匿名内部类使用(Java8新特性)
        (a,b) 参数类型可以不写,可以根据上下文自动推断
            推断依据?
                要求接口中只有一个抽象方法
                @FunctionalInterface  功能接口(java8)单抽象方法接口
                public interface Comparator
    */

    public static void main(String[] args) {
        String[] arr = {"c","a","d","b"};
        //用lambda表达式代替匿名内部类对象  将接口中的函数作为参数传递
        Arrays.sort(arr,(o1,o2)->{ return o2.compareTo(o1);});
        System.out.println(Arrays.toString(arr));
    }
}

在这里插入图片描述

4.Lambda表达式 示例

  1. 线程初始化
//匿名内部类方式
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("run...");
    }
}).start();

//Lambda表达式    
new Thread( ()->{System.out.println("run...");} ).start();             
  1. 排序
Arrays.sort(arr, new Comparator<String>() {
	@Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});

Arrays.sort(arr,(o1,o2)->{ return o1.compareTo(o2);});
	List<Integer> list = Arrays.asList(4,1,3,2);
    System.out.println(list);//[4, 1, 3, 2]
    list.sort((o1,o2)->{return o1.compareTo(o2);});
    System.out.println(list);//[1, 2, 3, 4]

  1. 事件处理
// 匿名内部类方式
button.addActionListener(new ActionListener() { 
	@Override 
	public void actionPerformed(ActionEvent e) {
	   System.out.println("Hello world"); 
	} 
}); 

// lambda 表达式方式 
button.addActionListener( (e) -> { System.out.println("Hello world"); });
  1. 遍历输出
	List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        //foreach遍历
        for (Integer i : list) {
            System.out.print(i+" ");
        }
        //Lambda表达式
        list.forEach(i->{
            System.out.print(i+" ");
        });

三、函数式接口(Functional Interface)

功能接口是Java8中新增特性,只允许一个抽象方法。这些接口也称为单抽象方法接口。它们也可以使用Lambda表达式,方法引用和构造函数引用来表示。

Java8引入了一个注释:@FunctionalInterface,当我们注释的接口违反了Functional Interface的规则时,会编译报错。

自定义功能接口示例:
Java8新特性_第11张图片
功能接口只能有一个抽象方法,如果在被@FunctionalInterface标注的接口中声明超过1个抽象方法,会抛出编译错误
Java8新特性_第12张图片
Multiple non-overriding abstract methods found in interface …
在该接口中发现了多个未重写的抽象方法

Java8允许我们以Lambda表达式的方式为功能接口提供实现,也就是说我们可以将整个Lambda表达式作为功能接口的实现类
例如:
功能接口
Java8新特性_第13张图片
lambda表达式实现接口
Java8新特性_第14张图片
Java8新特性_第15张图片
Java8 内置核心四大函数式接口
Java8新特性_第16张图片
其他函数式接口
Java8新特性_第17张图片

四、Optional类–解决空指针问题

Optional类可以解决空指针问题

以前处理空指针

	/**
     * 以前处理空指针
     */
    @Test
    public void test01(){
        //String name = "张三";
        String name = null;
        if(name!=null){
            System.out.println(name.length());
        }else{
            System.out.println("is null");
        }
    }

Optional类(自1.8之后)是一个没有子类的工具类,是一个值可以为Null的容器,主要作用是防止NullPointerException

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75VzLilM-1645615215062)(C:/Users/lanlei/AppData/Roaming/Typora/typora-user-images/1645608291225.png)]

Optional的常用方法:

创建Optional实例

  • Optional.of(T t) : 创建一个 Optional的实例对象, of()不支持null
  • Optional.empty(): 创建一个空的Optional实例
  • Optional.ofNullable(T t) : t为null创建空的Optional实例,不为null创建Optional实例
/**
     * 创建Optional对象
     */
    @Test
    public void test02(){
        //of(T t) 不支持null
        Optional<String> op1 = Optional.of("hello");//Optional[hello]
        //Optional op2 = Optional.of(null);//NullPointerException

        //empty) 创建一个空的实例
        Optional<String> op3 = Optional.empty();//Optional.empty

        //ofNullable(T t) 支持null
        Optional<String> op4 = Optional.ofNullable("hello");//Optional[hello]
        Optional<String> op5 = Optional.ofNullable(null);//Optional.empty
    }

其他常用方法

  • get() : 如果Optional有值就返回,否则抛出NoSuchElementException异常

  • isPresent() : 判断对象是否包含值,包含返回true,否则返回false

  • orElse(T t) : 如果对象包含值,返回该值,否则返回t

  • orElseGet(Supplier other) : 如果对象包含值,返回改值,否则返回Lambda表达式的返回值

  • ifPresent() : 如果值存在则使用该值调用 consumer , 否则不做任何事情。

/**
     * 常用方法
     * get():如果Optional有值就返回,否则抛出`NoSuchElementException`异常
     * isPresent(): 判断对象是否包含值,包含返回true,否则返回false
     * orElse(T t) : 如果对象包含值,返回该值,否则返回t
     * orElseGet(Supplier other) : 如果对象包含值,返回改值,否则返回Lambda表达式的返回值
     */
    @Test
    public void test03(){
        Optional<String> op1 = Optional.of("hello");
        Optional<String> op2 = Optional.empty();

        if(op1.isPresent()){
            System.out.println(op1.get());//hello
        }
        //System.out.println(op2.get());//抛出 NoSuchElementException 异常

        String s1 = op1.orElse("张三");
        System.out.println(s1);//hello  -->对象包含值,返回包含的值
        String s2 = op2.orElse("李四");
        System.out.println(s2);//李四   --> 对象不包含值,返回参数值

        String s3 = op2.orElseGet(() -> {
            return "hello";
        });
        System.out.println(s3);//hello -->对象不包含值,返回lambda表达式中的返回值
    }
	@Test
    public void test04(){
        Optional<String> op1 = Optional.of("hello");
        Optional<String> op2 = Optional.empty();

        //如果存在值,就执行...操作
        //op1.ifPresent(s-> System.out.println(s));
        op1.ifPresent(System.out::println);//hello
        op2.ifPresent(System.out::println);//没有值,不执行打印操作
    }

五、方法引用

对象::实例方法名

//Supplier中的T get()
//Employee中的String getName()
@Test
public void test2() {
    Employee emp = new Employee(1001,"Tom",23,5600);
    Supplier<String> sup1 = () -> emp.getName();
    System.out.println(sup1.get());

    Supplier<String> sup2 = emp::getName;
    System.out.println(sup2.get());
}

类::静态方法名

//Function中的R apply(T t)
//Math中的Long round(Double d)
@Test
public void test4() {
    Function<Double,Long> func1 = d -> Math.round(d);
    System.out.println(func1.apply(12.3));

    Function<Double,Long> func2 = Math::round;
    System.out.println(func2.apply(12.6));
}

类::实例方法名

// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5() {
    Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
    System.out.println(com1.compare("abc","abd"));

    Comparator<String> com2 = String::compareTo;
    System.out.println(com2.compare("abc","abe"));

}

// Function中的R apply(T t)
// Employee中的String getName();
@Test
public void test7() {
    Employee employee1 = new Employee(1001, "Jerry", 23, 6000);
    Function<Employee,String> func1 = e -> e.getName();
    System.out.println(func1.apply(employee1));

    Employee employee2 = new Employee(1001, "tom", 23, 6000);
    Function<Employee,String> func2 = Employee ::getName;
    System.out.println(func2.apply(employee2));
}

六、构造器引用、数组引用

  • 构造器引用格式: ClassName::new
  • 数组引用格式:type[] :: new

构造器引用要求构造器参数列表要与接口中抽象方法的参数列表一致!
且方法的返回值即为构造器对应类的对象

Java8新特性_第18张图片
数组引用

Java8新特性_第19张图片

七、接口中静态方法和默认方法

Java8之前接口中只能有全局常量和抽象方法
Java8引入了静态方法和默认方法

静态方法

接口名称.静态方法名(参数)

默认方法

Java8之前,在接口中只能声明抽象方法,不能声明有方法体的方法。

default方法是为了在原接口中扩展功能,但是对接口的实现类不会造成影响而出现的

例如Java源码中Iterable接口forEach和spliterator方法

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
//spliterator既可以像Iterator那样逐个迭代,也可以批量迭代。
//批量迭代可以降低迭代的开销。
default Spliterator<T> spliterator() {
     return Spliterators.spliteratorUnknownSize(iterator(), 0);
}

默认方法的继承问题

默认方法可以被继承,如果继承多个接口,多个接口有相同的默认方法,实现类需要重写默认方法

  1. 类优先:父类与接口定义了同名方法,默认实现父类的
  2. 优先重现子接口的更具体的方法
  3. 接口冲突:多个接口有参数列表和方法名相同的方法,不管是不是默认方法,实现类都必须去重写,否则程序不知道该调用哪个
    Java8新特性_第20张图片

你可能感兴趣的:(JavaSE笔记,java,前端,算法)