JAVA8新特性

JAVA8新特性

Lambda表达式

只有函数式接口才能使用Lambda表达式

​ Lambda表达式是JDK8中的一个语法糖,它可以对某些匿名内部类的写法进行简化,它是函数式编程思想的一个重要体现,让我们不用关注是什么对象,而是更关注我们对数据进行了什么操作。

核心原则

​ 可推导可省略

基本格式

(参数列表)-> {方法体(函数式接口方法的方法体)}

示例

1、

// 返回数组中能被2整除的数字 
printNum(x-> x % 2 == 0 );
 
 public static void printNum(IntPredicate predicate) {
    int[] arr = {1,2,3,4,5,6,7,8,9,10};
    for (int i : arr) {
        // predocate.test() 方法返回值为boolean类型
         if (predicate.test(i)) {
             System.out.println(i);
         }
    }
}

结果:

2
4
6
8
10

2、

    final Integer integer = typeConver(s -> {
        s += "78";
        return Integer.parseInt(s);
    });
    System.out.println(integer);
}

public static <R> R typeConver (Function <String, R > function){
    String str = "12345";
    R result = function.apply(str);
    return result;
}

结果:

1234578

Lambda核心是通过实现函数式接口的方法来完成相应业务

Lambda表达式的省略原则

没有参数,没有返回值的抽象方法
() -> {方法体语句}
如果方法体语句只有一句,此时可以省略大括号
() -> 方法体语句
有一个参数,没有返回值的抽象方法
(x)->{方法体语句}
如果只有一个参数,参数的小括号也可以省略不写
x -> {方法体语句}
有多个参数,没有返回值的抽象方法
(a,b)->{方法体语句}
有多个参数,有多条方法体语句,有返回值的抽象方法
(x,y)->{double pow = Math.pow(x,y);  return pow;};
如果语句只有一条,大括号可以省略,如果单语句是return语句,则return关键字也可以去掉,该格式会自动返回内容  写return关键字必须写大括号
(x,y)->Math.pow(x,y);

Stream流

​ JAVA8的Stream流使用的是函数式编程模式,如同他的而名字一样,它可以被用来对集合或者数据及逆行链状流式的操作。可以更方便的让我们对集合或者数组进行操作。

集合获取流对象的方式:

list、set:
	list/set.stream();
map:
	 hm.keyset().stream();
	 hm.values().stream();
	 hm.entryset().stream();
数组:
	Stream.of(arr);

中间操作

filter过滤操作

可以对流中的元素进行条件筛选,过滤条件为 true 的才会保存在流中

示例:

@Test
public void testStream() {
    List<Integer> list  = new ArrayList<>();
    for (int i = 1; i < 11; i++) {
        // 添加1-10
        list.add(i);
    }
    list.stream().filter(x -> x%2==0).forEach(System.out::println);
}

结果:

2
4
6
8
10
map

​ 可以对流中的元素进行计算或转换

  • 类型转换
// 定义一个 作者类
class Author {
    private String name;
    private Integer age;

    public Author() {
    }

    public Author(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

/*-------------------------------------------*/
List<Author> authors = new ArrayList<>();
authors.add(new Author("迪迦",10));
authors.add(new Author("戴拿",11));
authors.add(new Author("盖亚",12));
// 类型转换,匿名内部类方式实现
authors.stream()
    // 类型转换: 输入Author类型的参数,输出String类型的参数
    .map(new Function<Author, String>() {

    @Override
    public String apply(Author author) {
        return author.getName();
    }
}).forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});
}
// 类型转换,Lambda表达式实现
authors.stream().map(author -> author.getName()).forEach(s -> System.out.println(s));

结果:

迪迦
戴拿
盖亚
  • 计算
List<Author> authors = new ArrayList<>();
authors.add(new Author("迪迦",10));
authors.add(new Author("戴拿",11));
authors.add(new Author("盖亚",12));
authors.stream().map(author -> author.getAge()).map(age -> age + 10).forEach(age -> System.out.println(age));

结果:

20
21
22
distinct 去重

​ 可以去除流中的重复元素。

distinct方法是以来Object的equals方法来判断是否是相同的对象,所以集合中的对象需要重写equals方法

​ 示例:

​ 打印所有作家的名字,并且要求其中不能有重复元素


class Author {
    private String name;
    private Integer age;
	// 使用distinct操作必须重写equals和hashcode方法
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Author author = (Author) o;
        return Objects.equals(name, author.name) && Objects.equals(age, author.age);
    }
	// 显示对象数据必须重写toString方法
    @Override
    public String toString() {
        return "Author{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    public Author() {
    }

    public Author(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

List<Author> authors = new ArrayList<>();
authors.add(new Author("迪迦",10));
authors.add(new Author("戴拿",11));
authors.add(new Author("迪迦",10));
// 去重
authors.stream().distinct().forEach(author -> System.out.println(author.getName()));

结果:

迪迦
戴拿
sorted 排序

​ 可以都流当中的元素进行排序

示例:

​ 对流中的元素进行降序排序,并且要求不能有重复的元素

  1. 调用空参的 sorted 方法

注意: 调用空参的排序方法,对象要实现Comparable接口,并重写compareTo()方法自定义排序规则

// 实现Comparable接口
class Author implements Comparable<Author>{
    private String name;
    private Integer age;
	// 重写compareTo()方法自定义排序规则
    @Override
    public int compareTo(Author o) {
        return this.getAge() - o.getAge();
    }
}


List<Author> authors = new ArrayList<>();
authors.add(new Author("迪迦",12));
authors.add(new Author("戴拿",11));
authors.add(new Author("盖亚",10));
authors.add(new Author("阿古茹",19));
authors.add(new Author("迪迦",12));
authors.stream().distinct().sorted().forEach(author -> System.out.println(author));

结果:

Author{name='盖亚', age=10}
Author{name='戴拿', age=11}
Author{name='迪迦', age=12}
Author{name='阿古茹', age=19}

​ 2.调用有参的 sorted 方法

List<Author> authors = new ArrayList<>();
authors.add(new Author("迪迦",12));
authors.add(new Author("戴拿",11));
authors.add(new Author("盖亚",10));
authors.add(new Author("阿古茹",19));
authors.add(new Author("迪迦",12));
// 匿名内部类方式
authors.stream().distinct().sorted(new Comparator<Author>() {
    @Override
    public int compare(Author o1, Author o2) {
        return o1.getAge()- o2.getAge();
    }
}).forEach(author -> System.out.println(author));
// Lambda表达式方式
authors.stream().distinct()
    .sorted((o1, o2) -> o1.getAge()-o2.getAge())
    .forEach(author -> System.out.println(author));

结果:

Author{name='盖亚', age=10}
Author{name='戴拿', age=11}
Author{name='迪迦', age=12}
Author{name='阿古茹', age=19}
limit 截取

​ 可以设置流的最大长度,超出的部分将被抛弃

示例:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
l.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).limit(2).forEach(authors -> System.out.println(authors));

结果:

Authors{name='迪迦', age=10}
Authors{name='戴拿', age=11}
skip 截取

​ 跳过流中前size个元素,截取剩余元素

示例:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
l.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).skip(2).forEach(authors -> System.out.println(authors));

结果:

Authors{name='赛罗', age=13}
Authors{name='艾斯', age=16}
flatMap

​ 把一个对象转换成多个对象作为流中的元素

示例:

List<Book> l1 = new ArrayList<>();
l1.add(new Book("西游记","孙悟空三打白骨精"));
l1.add(new Book("红楼梦","黛玉葬花"));
List<Book> l2= new ArrayList<>();
l2.add(new Book("鲁滨逊漂流记","海上流浪汉"));
l2.add(new Book("红楼梦","黛玉葬花"));
List<Book> l3 = new ArrayList<>();
l3.add(new Book("三国演义","司马懿统一"));
l3.add(new Book("红楼梦","黛玉葬花"));
List<Book> l4= new ArrayList<>();
l4.add(new Book("西游记","孙悟空三打白骨精"));
l4.add(new Book("水浒传","鲁智深倒拔垂杨柳"));
List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10,l1));
l.add(new Authors("戴拿",11,l2));
l.add(new Authors("赛罗",13,l3));
l.add(new Authors("艾斯",16,l4));
l.stream()
        .flatMap(authors -> authors.getBooks().stream())//从作家对象中中获取书的流对象
    .distinct() // 对书对象去重
  .forEach(books -> System.out.println(books.getName())); // 打印书的名字

// 作家信息
class Authors {
    private String name;
    private Integer age;
    private List<Book> books;

    public Authors() {
    }

    @Override
    public String toString() {
        return "Authors{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", books=" + books +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Authors(String name, Integer age, List<Book> books) {
        this.name = name;
        this.age = age;
        this.books = books;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Authors authors = (Authors) o;
        return Objects.equals(name, authors.name) && Objects.equals(age, authors.age) && Objects.equals(books, authors.books);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, books);
    }
}
// 进行去重操作必须重写hashcode方法和equals方法
class Book {
    private String name;
    private String content;

    @Override
    public String toString() {
        return "Books{" +
                "name='" + name + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Book() {
    }

    public Book(String name, String content) {
        this.name = name;
        this.content = content;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Book book = (Book) o;
        return Objects.equals(name, book.name) && Objects.equals(content, book.content);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, content);
    }
}

结果:

西游记
红楼梦
鲁滨逊漂流记
三国演义
水浒传

终结操作

​ 以当前方法作为流操作的终结方法,之后不能再进行流操作。

​ 流操作时必须要有一个终结操作,这样中间操作才会生效。

forEach 遍历

​ 对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么操作

示例:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
l.stream().forEach(authors -> System.out.println(authors.getName()));

结果:

迪迦
戴拿
赛罗
艾斯
count 数量

​ 获取当前流中元素的个数

count()方法不需要参数但是有一个返回值,需要被接收

示例:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final long count = l.stream().filter(authors -> authors.getAge() > 10).count();
System.out.println(count);

结果:

3
max 最大值

​ 获取流中的最大值

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final Optional<Authors> max = l.stream().max((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(max.get());

结果:

Authors{name='艾斯', age=16, books=null}
min 最小值

​ 获取流中的最小值

示例:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final Optional<Authors> min = l.stream().min((o1, o2) -> o1.getAge() - o2.getAge());
System.out.println(min.get());

结果:

Authors{name='艾斯', age=16, books=null}
collect

​ 把当前流转换成一个集合

示例: toList\toSet

​ 获取一个存放所有作者名字的集合

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

final List<String> collect = l.stream().map(authors -> authors.getName()).collect(Collectors.toList());
System.out.println(collect);

结果:

[迪迦, 戴拿, 赛罗, 艾斯]

示例2: toMap

​ 获取一个Map集合,map的Key为姓名,value为年龄

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
// 匿名内部类方式实现
final Map<String, Integer> collect = l.stream().distinct().collect(Collectors.toMap(new Function<Authors, String>() {
    @Override
    public String apply(Authors authors) {
        return authors.getName();
    }
}, new Function<Authors, Integer>() {
    @Override
    public Integer apply(Authors authors) {
        return authors.getAge();
    }
}));
// Lambda表达式方式实现
final Map<String, Integer> collect = l.stream().distinct().collect(Collectors.toMap(authors -> authors.getName(), authors -> authors.getAge()));

System.out.println(collect);

结果:

{艾斯=16, 戴拿=11, 迪迦=10, 赛罗=13}
anyMatch

​ 判断是否有任意符合条件的元素,结果为boolean类型

示例:

​ 判断是否有年龄11岁以上的作家

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final boolean b = l.stream().anyMatch(authors -> authors.getAge() > 11);
System.out.println(b);

结果:

true
allMatch

​ 判断是否都符合匹配条件,结果为boolean类型。如果都符合结果为true,否则结果为false。

示例:

​ 是否年龄都为11岁以上的作家

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final boolean b = l.stream().allMatch(authors -> authors.getAge() > 11);
System.out.println(b);

结果:

false
noneMatch

​ 判断流中的元素是否都不符合匹配条件。如果都不符合结果为true,否则结果为false。

示例:

​ 是否作家年龄都不大于30岁

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));
final boolean b = l.stream().noneMatch(authors -> authors.getAge() > 30);
System.out.println(b);

结果:

true
findAny

​ 获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。

示例:

​ 获取任意一个年龄大于10的作家,如果存在就输出他的名字

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

final Optional<Authors> any = l.stream().filter(authors -> authors.getAge() > 10).findAny();
any.ifPresent(authors -> System.out.println(authors.getName()));

结果:

戴拿、赛罗、艾斯中的任意一个
findFirst

​ 获取流中的第一个元素

示例:

​ 获取一个年龄最小的作家的名字

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

final Optional<Authors> first = l.stream().sorted((o1, o2) -> {
    return o1.getAge()-o2.getAge();
}).findFirst();
first.ifPresent(authors -> System.out.println(authors.getName()));

结果:

迪迦
reduce 归并

​ 对流中的数据按照你制定的计算方式计算出一个结果

reduce内部的计算方式如下:

T result = identity; // 初始值
for (T element : this stream) // 遍历stream获取每个元素
	result = accumulator.apply(result,element);//计算方法
return result;

reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,他会按照我们的计算方式依次拿流中的元素和初始化值进行计算,计算结果再和后面的元素计算。

示例1:

T reduce(T identity, BinaryOperator<T> accumulator);

​ 求出所有作者的年龄的和

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

// 匿名内部类形式
final Integer reduce = l.stream().map(authors -> authors.getAge()).reduce(0, new BinaryOperator<Integer>() {
    @Override
    public Integer apply(Integer result, Integer element) {

        return result + element;
    }
});
// Lambda表达式
final Integer reduce = l.stream().map(authors -> authors.getAge()).reduce(0, (result, element) -> result + element);

System.out.println(reduce);

结果:

50

示例2:

​ 求所有作家中年龄的最大值

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

final Integer reduce = l.stream().map(authors -> authors.getAge()).reduce(Integer.MIN_VALUE, (result, element) -> result>element? result : element);
System.out.println(reduce);

结果:

16

示例3:

List<Authors> l = new ArrayList<>();
l.add(new Authors("迪迦",10));
l.add(new Authors("戴拿",11));
l.add(new Authors("赛罗",13));
l.add(new Authors("艾斯",16));

final Integer reduce = l.stream().map(author -> author.getAge()).reduce(Integer.MAX_VALUE, (result, element) -> result < element ? result : element);
System.out.println(reduce);

结果:

10

基本数据类型优化

​ 我们之前用到的很多Stream的方法都是由于使用了泛型。所以涉及到的参数和返回值都是引用数据类型。

​ 即使我们操作的是整数小数,但是实际用的都是他们的包装类。JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便,但是我们应该清楚装箱和拆箱是要消耗时间的,虽然这个时间消耗很小,但是在大量的数据不断的重复装箱拆箱时,你就不能无视这个时间损耗了。

​ 所以为了让我们能够对这部分时间消耗进行优化,Stream还提供了很多专门针对基本数据类型的方法。

​ 例如: mapToInt、mapToLong、mapToDouble、flatMapToInt、flatMapToDouble等。

示例:

private static void test() {
	List<Author> author = getAuthors();
	authors.stream()
	.map(author -> author.getAge())  // Integer
	.map(age -> age + 10) // Integer -> int ->Integer
    .filter(age -> age>18)// Integer -> int ->Integer
    .map(age->age+2) // Integer -> int ->Integer
    .forEach(System.out::println);    
}

优化:

private static void test() {
	List<Author> author = getAuthors();
	authors.stream()
	.mapToInt(author -> author.getAge())  // int
	.map(age -> age + 10) // int
    .filter(age -> age>18)// int
    .map(age->age+2) // int
    .forEach(System.out::println);    
}

并行流

​ 当流中有大量元素时,我们可以使用并行流去提高操作效率。其实并行流就是把任务分配给多个线程去完成。如果我们自己去用代码实现的话会非常复杂,并且要求你对并发编程有足够的理解和认识。而如果我们使用Stream的话,我们只需要修改一个方法的调用就可以使用并行流来帮我们实现,从而提高效率。

parallel方法课可以把串行流转换成并行流

也可以通过parallelStream直接获取并行流对象

private static void test() {
    Stream<Integer> Stream = Stream.of(1,2,3,4,5,6,7,8,9,10);
    Integer sum  = stream.parallel()
        .peek(new Consumer<Integer>() {
            @Override
            public void acept(Integer num) {
                System.out.println(num + Thread.currentThread().getName());
            }
        })
        .filter(num -> num>5)
        .reduce((result,ele) -> result + ele)
        .get();
    
}
List<Author> author = getAuthors();
author.parallelStream()
    .map(author->author.getAge())
    .map(age->age+10)
    .filter(age->age>18)
    .map(age->age+2)
    .forEach(System.out::println)

Optional

​ 本质上Optional是一个包装类,可以把我们具体数据封装到Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以避免空指针异常。

Optional静态方法

Optional.ofNullable

​ 使用ofNullable来把数据封装成一个Optional对象。无论传入的参数是否为null都不会报异常。

Author author = new Author("迪迦",12);
author = null;
// 如果optional对象存在则进行消费
final Optional<Author> author1 = Optional.ofNullable(author);
author1.ifPresent(author2 -> System.out.println(author2.getAge()));

结果:

当author不为null时,  结果为12
当author为null时, 结果没有结果但是也不报错    
Optional.of

​ 如果你确定一个对象不为空,则可以使用Optional.of方法把数据封装成Optional对象。

如果对象为null,则会报出空指针异常

Author author = new Author("迪迦",12);
final Optional<Author> author2 = Optional.of(author);
author2.ifPresent(author3 -> System.out.println(author3.getAge()));

author = null;
final Optional<Author> author1 = Optional.of(author);
System.out.println(author1);
author = 

​ 结果:

12
npe 
Optional.empty

​ 将null封装成Optional对象。

Author author = new Author("迪迦",12);
author = null;
final Optional<Object> empty = Optional.empty();
// 判断值是否为null
System.out.println(empty.isEmpty());

​ 结果:

true

安全消费值

​ 如果一个对象是Optional对象,则可以调用消费接口进行消费,这个方法会判断Optional中封装的数据是否为空,不为空才会执行具体的消费代码。

这种写法可以避免空指针异常

Author author = new Author("迪迦",12);
author = null;
// 如果optional对象存在则进行消费
final Optional<Author> author1 = Optional.ofNullable(author);
author1.ifPresent(author2 -> System.out.println(author2.getAge()));

结果:

12

获取值

如果我们想获取值可以使用get方法获取,但是不推荐,因为当Optional内部的数据为空的时候会出现异常。

NoSucElement异常

Author author = new Author("迪迦",12);
final Optional<Author> author1 = Optional.ofNullable(author);
final Author author2 =
        author1.get();
System.out.println(author2);

author = null;
final Optional<Author> author3 = Optional.ofNullable(author);
final Author author4 = author3.get();
System.out.println(author4);

结果:

Author{name='迪迦', age=12}

Exception in thread "main" java.util.NoSuchElementException

安全获取值

orElseGet

​ 获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据,如果为空则根据你传入的参数来创建对象作为默认值进行返回。

示例:

Author author = new Author("迪迦",12);
// author = null;
Optional<Author> author1 = Optional.ofNullable(author);
Author author2 = author1.orElseGet(() -> new Author("戴拿",14));
System.out.println(author2);

结果:

// 当author不为空时,显示结果
Author{name='迪迦', age=12}
// 当author为null时,显示结果
Author{name='戴拿', age=14}
orElseThrow

​ 获取数据,如果数据不为空就能获取到该数据,如果为空则根据你传入的参数来创建异常抛出。

示例:

Author author = new Author("迪迦",12);
final Optional<Author> author1 = Optional.ofNullable(null);
final Author author2 = author1.orElseThrow(() -> new RuntimeException("测试异常"));
System.out.println(author2);

结果:

Exception in thread "main" java.lang.RuntimeException: 测试异常
	at com.Day23.newCharacter.Optional类.lambda$main$0(Optional.java:16)
	at java.base/java.util.Optional.orElseThrow(Optional.java:408)
	at com.Day23.newCharacter.Optional类.main(Optional.java:16)

过滤

​ 使用filter方法过滤出符合条件的Optional对象

示例:

Author author = new Author("迪迦",12);
final Optional<Author> author1 = Optional.ofNullable(author);
final Optional<Author> author3 = author1.filter(author2 -> author2.getAge() > 10);
System.out.println(author3);

结果:

// 当满足条件age为12时
Optional[Author{name='迪迦', age=12}]
// 当不满足条件age为10时,返回一个value为null的新的Optional对象
Optional.empty

判断

​ 可以使用isPresent/ifPresent方法判断是否存在数据。如果为空,返回值为false;如果不为空,返回值为true

推荐使用ifPresent,因为ifPresent更能体现Optional的优势

示例:

Author author = new Author("迪迦",12);
author = null;
// 如果optional对象存在则打印年龄
final Optional<Author> author1 = Optional.ofNullable(author);
author1.ifPresent(author2 -> System.out.println(author2.getAge()));

结果:

// 当Optional对象存在时
12
// 当Optional对象不存在时
什么也不显示

数据转换

​ Optional提供了map方法对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全。

示例:

// 将author转换为List<Book>
List<Book> l1 = new ArrayList<>();
l1.add(new Book("西游记","孙悟空三打白骨精"));
l1.add(new Book("红楼梦","黛玉葬花"));
final Optional<Authors> author = Optional.ofNullable(new Authors("迪迦", 12, l1));
Optional<List<Book>> books = author.map(authors -> authors.getBooks());
if (books.isPresent()) {
    System.out.println(books);
}

结果:

Optional[[Books{name='西游记', content='孙悟空三打白骨精'}, Books{name='红楼梦', content='黛玉葬花'}]]

方法引用

​ 简化Lambda表达式的语法糖

基本格式

类名或者对象名::方法名

语法详解

引用类的静态方法

使用前提:

​ 如果我们在重写方法的时候,方法体中只有一行代码并且这行代码是调用了某个类的静态方法,并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法

格式
类名::方法名

示例:

List<Author> list = new ArrayList<>();
list.add(new Author("迪迦",12));
list.add(new Author("戴拿",11));
list.add(new Author("盖亚",10));
list.add(new Author("阿古茹",19));
list.add(new Author("迪迦",12));

list.stream().map(author -> author.getAge())
        .map(new Function<Integer, String>() {
            @Override
            // 1、方法体中只有一行代码
            public String apply(Integer integer) {
                // 2、调用了某个类的静态方法
                // 3、把重写的抽象方法中的所有参数都按照顺序传入这个静态方法
                return String.valueOf(integer);
            }
        });

优化:


List<Author> list = new ArrayList<>();
list.add(new Author("迪迦",12));
list.add(new Author("戴拿",11));
list.add(new Author("盖亚",10));
list.add(new Author("阿古茹",19));
list.add(new Author("迪迦",12));

list.stream().map(author -> author.getAge())
              .map(String::valueOf);
引用对象的实例方法
格式
对象名::方法名

使用前提:

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法

List<Author> list = new ArrayList<>();
    list.add(new Author("迪迦",12));
    list.add(new Author("戴拿",11));
    list.add(new Author("盖亚",10));
    list.add(new Author("阿古茹",19));
    list.add(new Author("迪迦",12));
// 创建对象 
StringBuilder sb = new StringBuilder();
list.stream().map(author -> author.getName())
    .forEach(new Consumer<String>() {
    @Override
    // 1、方法体中只有一行代码
    public void accept(String s) {
        // 2、代码调用了某个对象的成员方法
        // 3、抽象方法中的所有参数都按照顺序传入了这个成员方法中
        sb.append(s);
    }
});

优化:

List<Author> list = new ArrayList<>();
    list.add(new Author("迪迦",12));
    list.add(new Author("戴拿",11));
    list.add(new Author("盖亚",10));
    list.add(new Author("阿古茹",19));
    list.add(new Author("迪迦",12));
StringBuilder sb = new StringBuilder();
list.stream().map(author -> author.getName()).forEach(sb::append);
引用类的实例方法
格式:
类名::方法名

使用前提:

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法

public class MethodInfrence{
    interface UserString {
        String use(String str,int start,int end);
    }

    public static String subAuthorName(String str,UserString useString) {
        int start = 0;
        int end = 1;
        return useString.use(str,start,end);
    }
    public static void main(String[] args) {
        subAuthorName("迪迦", new UserString() {
            // 1、方法体中只有一行代码
            @Override
            public String use(String str, int start, int end) {
                // 2、这行代码调用了第一个参数的成员方法
                // 3、抽象方法中剩余的所有参数都按照顺序传入了这个成员方法中
                return str.substring(start,end);
            }
        });
    }
}    

优化:

public class MethodInfrence{
    interface UserString {
        String use(String str,int start,int end);
    }

    public static String subAuthorName(String str,UserString useString) {
        int start = 0;
        int end = 1;
        return useString.use(str,start,end);
    }
    public static void main(String[] args) {
        subAuthorName("迪迦", String::substring);
    }
}    
构造器引用

使用前提:

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器

​ 如果方法体中的一行代码是构造器的话就可以使用构造器引用

格式
类名::new

示例:

List<Author> list = new ArrayList<>();
list.add(new Author("迪迦",12));
list.add(new Author("戴拿",11));
list.add(new Author("盖亚",10));
list.add(new Author("阿古茹",19));
list.add(new Author("迪迦",12));

list.stream().map(author -> author.getName())
        .map(new Function<String, StringBuilder>() {
            @Override
            // 1、方法体只有一行代码
            public StringBuilder apply(String s) {
                // 2、这行代码调用了某个类的构造方法
                // 3、抽象方法中所有的参数都按照顺序传入了这个构造方法中
                return new StringBuilder(s);
            }
        })
        .map(sb -> sb.append("--123"))
        .forEach(str -> System.out.println(str));

优化:

List<Author> list = new ArrayList<>();
list.add(new Author("迪迦",12));
list.add(new Author("戴拿",11));
list.add(new Author("盖亚",10));
list.add(new Author("阿古茹",19));
list.add(new Author("迪迦",12));

list.stream().map(author -> author.getName())
        .map(StringBuilder::new)
        .map(sb -> sb.append("--123"))
        .forEach(str -> System.out.println(str));
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值