函数式编程-Stream流

函数式编程-Stream流

1.概述

1.1好处

  • 大数量下处理集合效率高

  • 代码可读性高

  • 消灭嵌套

1.2函数式编程思想

1.2.1概念

​ 面向对象思想需要关注用什么对象完成什么事情。而函数式编程思想就类似于我们数学中的函数。它主要关注的是对数据进行了什么操作。

1.2.2优点
  • 代码简洁
  • 接近自然语言,易于理解
  • 易于"并发编程"

2.Lambda表达式

2.1概述

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

2.2基本格式

(参数列表)->{代码}

只有一行代码时,大括号可省略

例一

创建线程并启动时可以使用匿名内部类的写法:

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("你知道吗 我比你想象的 更想在你身边");
            }
        }).start();
    }

可以使用Lambda的格式进行修改。修改后如下:

        new Thread(()->{
            System.out.println("你知道吗 我比你想象的 更想在你身边");
        }).start();

2.3 省略规则

  • 参数类型可以省略
  • 方法体只有一句代码时大括号return和唯一一句代码分号可以省略
  • 方法只有一个参数时小括号也可以省略
  • 以上规则记不住也可以不记

3. stream流

3.1 概述

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

3.2 案例数据准备

创建两个实体类

package day17;

import java.util.List;

public class Author {
    private String name;
    private int age;
    private List<Book> bookList;

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public List<Book> getBookList() {
        return bookList;
    }

    public void setBookList(List<Book> bookList) {
        this.bookList = bookList;
    }
}

package day17;

import java.util.Objects;

public class Book {
    private String bookName;
    private String author;
    private int price;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @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(bookName, book.bookName) && Objects.equals(author, book.author);
    }

    @Override
    public int hashCode() {
        return Objects.hash(bookName, author);
    }

    public Book(String bookName, String author, int price) {
        this.bookName = bookName;
        this.author = author;
        this.price = price;
    }

    public Book() {
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

准备数据

  List<Book> list= new ArrayList<>();
        list.add(new Book("斗罗大陆","唐家三少",18));
        list.add(new Book("斗破苍穹","天蚕土豆",22));
        list.add(new Book("武动乾坤","天蚕土豆",19));
        list.add(new Book("斗破苍穹","天蚕土豆",22));

        List<Book> list1 = new ArrayList<>();
        List<Author> authorList = new ArrayList<>();
        list1.add(new Book("斗罗大陆","唐家三少",18));
        list1.add(new Book("神印王座","唐家三少",21));
        Author author = new Author();
        author.setName("唐家三少");
        author.setAge(27);
        author.setBookList(list1);
        List<Book> list2 = new ArrayList<>();
        list2.add(new Book("斗破苍穹","天蚕土豆",22));
        list2.add(new Book("武动乾坤","天蚕土豆",19));
        list2.add(new Book("斗破苍穹","天蚕土豆",22));
        Author author1 = new Author();
        author1.setName("天蚕土豆");
        author1.setAge(32);
        author1.setBookList(list2);
        authorList.add(author);
        authorList.add(author1);

3.3 快速入门

3.3.1 需求

将所有书籍价格大于20且不重复的书籍输出

3.3.2 实现
// 将所有书籍的价格大于20且不重复的书籍输出:使用filter过滤掉书籍价格少于20的书籍
       list.stream()
               .filter(book -> book.getPrice()>20)
               .distinct()
               .forEach(book -> System.out.println(book));

3.4 常用操作

3.4.1 创建流

单列集合:集合对象.stream()

Stream<Book> stream = list.stream();

数组:Arrays.stream(数组)或者使用Stream.of来创建

Integer[] arr = {1,2,3,4,5}
Stream<Integer> stream = Arrays.stream(arr);
Stream<Integer> stream1 = Strea.of(arr);

双列集合:转换成单列集合后再创建

Map<String,Integer> map = new HashMap<>();
map.put("萧炎",22);
map.put("小黑子",21);
map.put("坤坤",20);
Stream<Map,Entry<String,Integer>> stream = map.entrySet().stream();
3.4.2 中间操作
filter

​ 可以对流中的元素进行过滤,符合条件的才能继续留在流中

例如:

​ 打印书籍价格大于18的书籍名称

       list.stream()
               .filter(book -> book.getPrice()>18)
               .forEach(book -> System.out.println(book.getBookName()));
map

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

例如:

​ 将所有的书籍价格加15并去重(返回书籍的所有信息),使用map方法,实现Function接口中的apply方法

list.stream()
        .distinct()
        .map(book -> {
            book.setPrice(book.getPrice() + 15);
            return book;
        })
        .forEach(System.out::println);
distinct

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

例如:

​ 将所有书籍的价格大于20且不重复的书籍输出

// 将所有书籍的价格大于20且不重复的书籍输出:使用filter过滤掉书籍价格少于20的书籍
       list.stream()
               .filter(book -> book.getPrice()>20)
               .distinct()
               .forEach(book -> System.out.println(book));
sorted

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

例如:

​ 将所有书籍用价格进行排序(升序/降序排列),并去重,使用sorted方法

list.stream()
        .distinct()
        .sorted((book1, book2) -> book2.getPrice()-book1.getPrice())
        .forEach(System.out::println);
limit

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

例如:

​ 将所有书籍去重,选出价格最大的一本书籍

list.stream()
        .distinct()
        .sorted((o1,o2)-> o2.getPrice()-o1.getPrice())
        .limit(1)
        .forEach(System.out::println);
skip

​ 跳过流中的前n个元素,返回剩下的元素

例如:

​ 将除了价格最大的书籍以外的其它书籍打印出来

list.stream()
        .distinct()
        .sorted(((o1, o2) -> o2.getPrice()-o1.getPrice()))
        .skip(1)
        .forEach(System.out::println);
flatMap

​ map只能把一个对象转换成另一个对象来作为流中元素,而flatMap可以把一个对象转换成多个对象作为流中的元素(多数使用在实体类中有list的情况),

flatMap方法返回的是一个流对象。

例如:

​ 打印作家的所有书籍

authorList.stream()
        .flatMap(author2 -> author2.getBookList().stream())
        .distinct()
        .forEach(System.out::println);
3.4.3 终结操作
forEach

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

例子:

​ 输出所有书籍

list.stream()
	    .forEach(System.out::println);
count

​ 可以用来获取流中元素的个数。

例子:

​ 求出流中不重复书籍的数量

long count = list.stream()
        .distinct()
        .count();
System.out.println("不重复的书籍数量为:"+count);
max&min

​ 用于求流中的最值

例子:

​ 打印出书籍中最大的书籍价格

Optional<Integer> max = list.stream()
        .map(book -> book.getPrice())
        .max((price1, price2) -> price1 - price2);
System.out.println(max.get());
collect

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

例子:

​ 将不重复书籍的名称转换成集合并打印

List<String> nameList = list.stream()
        .distinct()
        .map(book -> book.getBookName())
        .collect(Collectors.toList());
System.out.println(nameList);

​ 将不重复书籍的名称转换成set集合并打印

Set<String> nameSet = list.stream()
        .distinct()
        .map(book -> book.getBookName())
        .collect(Collectors.toSet());
System.out.println(nameSet);

​ 将不重复的书籍名称转换成Map集合并打印

Map<String, Integer> nameMap = list.stream()
        .distinct()
        .collect(Collectors.toMap(new Function<Book, String>() {
            @Override
            public String apply(Book book) {
                return book.getBookName();
            }
        }, new Function<Book, Integer>() {
            @Override
            public Integer apply(Book book) {
                return book.getPrice();
            }
        }));
System.out.println(nameMap);
anyMatch

​ 可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型

例子:

​ 判断是否有书籍价格大于22的书籍

boolean b = list.stream()
        .distinct()
        .map(book -> book.getPrice())
        .anyMatch(integer -> integer > 22);
System.out.println(b);
allMatch

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

例子:

​ 判断所有书籍价格是否都大于18

boolean b1 = list.stream()
        .distinct()
        .map(book -> book.getPrice())
        .allMatch(integer -> integer > 18);
System.out.println(b1);
noneMatch

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

例子:

​ 判断所有书籍价格都不超过50

boolean b2 = list.stream()
        .map(book -> book.getPrice())
        .noneMatch(integer -> integer >= 50);
System.out.println(b2);
findAny

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

例子:

​ 随机获取流中价格大于17的元素,并打印

Optional<Book> any = list.stream()
        .distinct()
        .filter(book -> book.getPrice()>17)
        .findAny();
System.out.println(any.get());
findFirst

​ 用于获取流中的第一个元素

例子:

​ 获取流中价格最大的书籍并打印

Optional<Book> first = list.stream()
        .filter(book -> book.getPrice() > 17)
        .sorted((book1,book2)->book2.getPrice()-book1.getPrice())
        .distinct()
        .findFirst();
System.out.println(first.get());
reduce归并

​ 对流中的书籍按照规定的计算方式计算出一个结果。

​ reduce的作用是把Stream中的元素组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和在初始化值的基础上进行计算技术结果再和后面的元素计算。

​ 它内部的计算方式如下:

T result = identity;
for(T element:this stream)
	result = accumulator.apply(result,element)
return result;

​ 其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算,也是我们通过方法参数来确定的。

例子:

​ 求所有书籍价格的总和并打印

Integer sum = list.stream()
        .map(book -> book.getPrice())
        .reduce(0, (result, element) -> result+element);
System.out.println(sum);

​ 使用reduce求出书籍中价格最高的书籍并打印

Integer priceMax = list.stream()
        .map(book -> book.getPrice())
        .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
System.out.println(priceMax);

使用单个参数的方法,默认流中的第一个元素就是result

Integer priceMax = list.stream()
        .map(book -> book.getPrice())
        .reduce((result, element) -> result < element ? element : result);
System.out.println(priceMax);

3.5 stream流注意事项

  • 惰性求值(如果没有终结操作,没有中间操作是不会得到执行的)
  • 流是一次性的(一旦一个流对象经过一个终结操作之后。这个流就不能再被使用)
  • 不会影响原数据(我们在流中可以多数据做很多处理。但正常情况下是不会影响原来集合中的元素的。)

3.6 调试流

  1. 在需要调试的流上打上断点

  2. 调试时点击流的专用调试工具

函数式编程-Stream流_第1张图片
这个工具可以帮助我们查看流的每一步操作过程

你可能感兴趣的:(开发语言,java)