一、基本介绍
"函数式编程"是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。 它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用。
函数式编程优点:
- 代码简介开发迅速
- 接近自然语言,易于理解
- 易于并发编程
二、Lambda表达式
1、优点
不关注对象是什么,不关注方法名是什么,只关注如何操作数据 可推导可省略 对匿名内部类(是接口且仅有一个抽象方法)进行简化
2、基本格式
(参数列表)->{代码}
例1:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Lambda表达式学习");
}
}).start();
new Thread(() -> {
System.out.println("Lambda表达式学习");
}).start();
例2:
@FunctionalInterface
public interface IntBinaryOperator {
int applyAsInt(int left, int right);
}
public static int calculateNum(IntBinaryOperator operator) {
int a = 20;
int b = 10;
return operator.applyAsInt(a, b);
}
int i = calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
int i = calculateNum((left, right) -> {
return left + right;
});
例3:
@FunctionalInterface
public interface IntPredicate {
boolean test(int value);
}
public static void printNum(IntPredicate predicate) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
if (predicate.test(i)) {
System.out.println(i);
}
}
}
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value % 2 == 0;
}
});
printNum((value)->{
return value%2==0;
});
3、进一步优化
- 参数类型可以省略(上述例子全部省略)
- 方体体只有一句代码时,大括号、return、分号可以省略例如:
如例3 可写为: printNum((value) -> value % 2 == 0); - 方法体只有一个参数时小括号也可以省略
再改写:printNum(value -> value % 2 == 0);
三、方法引用
lambda表达式再一次改进 基本格式: 类名或对象名::方法名
什么时候用?
我也不太懂 只会alter+enter
例: .mapToInt(author -> author.getAge()) 改进:.mapToInt(Author::getAge)
四、Stream流🔺
1、简介
优点:更加简便的操作集合和对象
2、准备案例
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Author{
private Long id;
private String name;
private int age;
private List<Book> books;
public Integer getHHH(int age,String name){
return Integer.valueOf(age+name);
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
private Long id;
private String title;
private String category;
private double price;
}
private static List<Author> getAuthors() {
Book book = new Book(1L, "JavaSE", "JAVA", 200);
Book book1 = new Book(2L, "Python精通", "Python", 205);
Book book2 = new Book(3L, "JAVAEE", "JAVA", 28);
Book book3 = new Book(4L, "C++Prime", "C++", 2254);
Book book4 = new Book(5L, "JAVAWeb", "JAVA,Web", 445);
Book book5 = new Book(6L, "Redis", "database,Linux", 54);
Book book6 = new Book(7L, "Mysql", "database", 545);
List<Book> list = new ArrayList<>();
List<Book> list1 = new ArrayList<>();
List<Book> list2 = new ArrayList<>();
list.add(book);
list.add(book1);
list.add(book2);
list.add(book2);
list1.add(book3);
list1.add(book4);
list2.add(book6);
list2.add(book6);
list2.add(book5);
Author author = new Author(1L, "Mae", 21, list);
Author author1 = new Author(2L, "Strive", 25, list1);
Author author2 = new Author(3L, "Naomi", 28, list2);
Author author3 = new Author(3L, "Naomi", 28, list2);
return new ArrayList<>(Arrays.asList(author, author1, author2, author3));
}
3、创建流操作
-
单列集合:集合对象.stream()
List<Author> authorList=getAuthorList();
authorList.stream();
-
多列集合:map.entrySet.stream();
Map<String,String> map=new HashMap<>();
map.entrySet.stream();
-
数组:Arrays.stream(数组名)
4、中间操作(过滤、排序、去重、转换等等)
(1)、filter
过滤操作 例:输出年龄大于25的作家
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getAge()>25)
.forEach(author -> System.out.println(author));
过滤后只剩下两条
(2)、distinct
去重 案例:打印年龄超过25的作家 并且去重
List<Author> authors = getAuthors();
authors.stream()
.filter(author -> author.getAge()>25)
.distinct()
.forEach(author -> System.out.println(author));
(3)、map
对流中的元素进行计算或转换(类型) 例:将对象按照年龄转成Integer 然后将年龄加10
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getAge())
.distinct()
.map(age -> age + 10)
.forEach(age -> System.out.println(age));
(4)、sorted
排序 例:按照年龄降序
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getAge())
.distinct()
.sorted((o1, o2) -> o2-o1)
.forEach(age -> System.out.println(age));
(5)、limit
限制流的最大长度 案例:打印年龄最大的两个作家(需去重和排序)
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.limit(2)
.forEach(author -> System.out.println(author));
(6)、skip
跳过所定义长度的流 案例:打印除了最大年龄的所有作家
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge() - o1.getAge())
.skip(1)
.forEach(author -> System.out.println(author));
(7)、flatmap
将一个对象转换成多个对象 例 打印所有书籍名字 并去除
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book ));
使用 flatmap 将一个作家集合转换成多个书本集合
例 打印所有书本分类 并去重(注意属于多个分类的书籍)
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
.distinct()
.forEach(s -> System.out.println(s));
关键:将属于多个分类的书籍 用逗号分隔转换成数组,然后再用数组的stream()方法 转化成流
5、终结操作
终结操作是stream流中必须的,如果没有终结操作,那么中间操作将不会执行
(1)、forEach
对流中的元素进行遍历 前面的案例都用forEach作为终结操作
(2)、count
获取流中元素个数 例:获取书本个数(去重)
(3)、min&max
获取流中元素的最小值和最大值 例:获取年龄最大的作者
(4)、collect
把当前流转换成一个集合 案例 转成成set集合 键为作者,值为书名
List<Author> authors = getAuthors();
Map<String, List<Book>> map = authors.stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
(5)、anyMatch
判断是否有符合匹配条件的元素 例:判断是否有年龄大于25的作家
List<Author> authors = getAuthors();
boolean b = authors.stream()
.anyMatch(author -> author.getAge() > 25);
(6)、allMatch
判断所有元素是否都符合条件
(7)、noneMatch
判断是否都不符合条件
(8)、findAny
找到任意一个符合条件的元素
(9)、findFirst
找到第一个符合条件的元素
(10)、reduce🔺
对流中的数据按照指定规则方式计算出一个结果 例 求作者年龄之和(去重)
List<Author> authors = getAuthors();
Integer sum = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, (result, age) -> (result + age));
System.out.println(sum);
6、基本数据类型转化优化
不使用map,而使用mapToInt/Double/Long、flatMapToInt/Double/Long
List<Author> authors = getAuthors();
authors.stream()
.mapToInt(author -> author.getAge())
.forEach(value -> System.out.println(value));
7、Stream流总结
- 流是惰性求值,即不进行终结操作,中间操作也不会执行
- 流是一次性的,对一个集合创建了流,不能再对其进行第二次创流
- 不影响原数据
四、Optional🔺
1、作用
主要为了避免开发过程中出现空指针异常 空指针确实很烦 Exception in thread "main" java.lang.NullPointerException
2、使用Optional避免空指针异常
使用ofNullable获取对象(无论是否为空) 使用ifPresent 如果不为空则执行 为空则不会执行
List<Author> authors = getAuthors();
Optional<List<Author>> authorListOptional = Optional.ofNullable(authors);
authorListOptional.ifPresent(authors1 -> System.out.println(authors1));
3、有关Optional
Optional中还有许多方法与Stream流中类似 不演示了
|