# 函数式编程

Functional programming

面向函数编程是将行为抽象为一个函数,将一件事情分成若干个行为(函数),编程的本质是组合,组合的本质是范畴(Category),范畴是函数的组合。

核心思想

  • 面向对象关注什么对象完成什么事情(数据),面向函数关注完成事情的操作

  • 函数式编程,集中点在函数,函数可以作为参数,返回值,具有不可变性(传递的参数相同结果肯定相同)

优点:

  • 处理集合效率高
  • 代码可读性高、简洁
  • 减少嵌套

# Lambda 表达式

Lambda 起始于 JDK8,是 java8 中的一个语法糖,可以对匿名内部类的写法进行简化,是函数式编程的重要体现,让我们不关注对象本身而是关注数据做了什么。

# 核心原则

  • 可推导可省略

# 设计原则

  • 单一原则
  • 开放闭合原则

# 格式

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

栗子:

创建线程执行特定操作:

(匿名内部类构造方法传入 Runnable 接口实现):

new Thread(new Runnable(){
	@Override
    public void run() {
        System.out.println();
    }
}).start();

Lambda 写法:

new Thread(()->{
    System.out.println();
}).start();

大概总结(伪代码):

new Class(new Interface(){
	@Override
	public T function(? a){
		pass;
	}
});
new Class((? a) -> {pass});

关注点:括号内参数,大括号内代码

# 省略规则

  • 💥参数类型可以省略!

  • 🎈方法体只有一句代码时大括号 return 和唯一 一句代码分号可以省略

  • 😲方法只有一个参数小括号也可以省略

new Thread(() -> System.out.println("mmyser")).start();

# Stream 流

Java8 的 Stream 使用的是函数式编程模式,可以用来对集合和数组进行链状流氏的操作。

# 流的使用

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Author {
    private Long id;
    private String name;
    private Integer age;
    private String intro;
    private List<Book> books;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
    private Long id;
    private String name;
    private String category;
    private Integer score;
    private String intro;
}
authorList.stream()
          .distinct()// 去重
    		// 过滤器
          .filter(new Predicate<Author>() {
               @Override
               public boolean test(Author author) {
                   return author.getAge() < 18;
               }
          })
    		// 增强循环
          .forEach(new Consumer<Author>() {
               @Override
               public void accept(Author author) {
                   System.out.println(author.getName());
               }
          });

lambda:

authorList.stream()
                .distinct()
                .filter(author12 -> author12.getAge() < 18)
                .forEach(author1 -> System.out.println(author1.getName()));

# 常用操作

# 创建流

单列集合(实现接口 Collection): 对象.stream

List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();

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

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

双列集合(实现接口 Map):转换成单列集合后再进行创建;

Map<String,Integer> map = new HashMap<>();
map.put("蜡笔小新",19);
map.put("黑子",17);
map.put("日向翔阳",16);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

# 中间操作

# filter

通过条件过滤流中的元素

# map

将流中的元素进行转换和计算

# distinct

取出流中的重复元素

依照 equal () 方法来进行判重

# sorted

对流中的元素进行排序

authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .forEach(author -> System.out.println(author));
//
authors.stream()
                .sorted(Comparator.comparingInt(Author::getAge))
                .forEach(System.out::println);

无参方法要求元素需要实现 Comparable 接口( compareTo() 方法)

# limit

设置流的最大长度

# skip

跳过流中的 n 个元素

# flatMap

将流中一个对象转换成多个对象

List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(category-> System.out.println(category));

# 终结操作

# forEach

对流中的元素进行遍历并进行具体操作

# count

获取流中元素的个数 (返回类型 long)

Long num = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .count();
        System.out.println(num);

# max&min

获得流中的最值

Optional<Integer> optional = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((score1, score2) -> score1 - score2);
        System.out.println(optional.get());

# collect

将流转换成一个集合

List<String> list = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(list);
Set<Book> set = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(set);
Map<String, Object> map = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(map);

# anyMatch

判断是否有任意符合匹配条件的元素(返回布尔类型)

boolean flag = authors.stream()
                .anyMatch(author -> author.getAge() < 18);

# allMatch

用来判断是否都符合条件(返回布尔类型)

# noneMatch

判断流中元素是否都不符合匹配条件(返回布尔类型)

# findAny

获取流中任意一个元素(返回 Optional 类型)

Optional<Author> optional = authors.stream()
                .filter(author -> author.getAge() >28)
                .findAny();
        optional.ifPresent(author -> System.out.println(author));

# findFirst

获取流中第一个元素

# 💥reduce

对流中的数据按照指定 计算方式计算出一个结果(缩减)

内部逻辑

T result = identity
for(T element : this stream)
	result = accumulator.apply(result, element)
return result;
int sum = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (result, element) -> result + result);

reduce 一个参数重载形式内部的计算

boolean foundAny = false;
T result = null;
for(T element : this stream){
	if(!foundAny = true) {
		foundAny = true;
		result = element;
	} else {
		result = accumulator.apply(result, element);
	}
	return foundAny ? Optional.of(result) : Optional.emmpty();
}

# 注意事项

  • 如果没有终结操作,中间操作不会执行
  • 流是一次性的,只能经过一个终结操作
  • 流的操作不会影响元数据

# 参考

  • 三更草堂
  • 慕课教程
更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝