耗时十五天的期末考试终于结束了,搞起来。
文章总结B站三更草堂。
1. 函数编程
- 函数式编程思想类似于数学中的函数,主要关注的是对数据进行了什么操作。
- 优点:
- 大数据处理集合效率高——使用并行流来处理数据;
- 可读性高;
- 代码简介,快速开发。
1.1 lambda表达式
是JDK8中的一个语法糖,可以对某些匿名内部类的写法进行优化,是函数式编程思想的一个重要体现,不关注是什么对象,更关注对数据进行了说明操作。
- 核心原则:可推导可省略;
- 基本格式:
( 参数列表 ) -> {代码}
1.1.1 lambda表达式用法举例
在方法调用传入匿名内部类时,在匿名内部类使用idea的快捷键:alt + enter
可以选定lambda表达式。
-
多线程创建方式:
- 普通方法创建线程:
new Thread(new Runnable() { @Override public void run() { System.out.println("普通方法创建线程"); } }).start();
- lambda创建线程:
new Thread(() -> { System.out.println("lambda 创建线程"); }).start();
-
自定义方法:
- 自定义方法:
public static int calculateNum(IntBinaryOperator operator){ int a = 10; int b = 20; return operator.applyAsInt(a, b); }
- 普通调用方法:
int retInt = calculateNum(new IntBinaryOperator() { @Override public int applyAsInt(int left, int right) { return left + right; } }); System.out.println(retInt);
- 简化:
int lamRet = calculateNum((int left, int right) -> { return left + right; }); System.out.println(lamRet);
-
自定义方法2:
- 定义方法:
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; } });
- lambda简化:
printNum(value -> value % 2 == 0);
- 定义方法:
-
自定义方法3:
- 定义方法:
public static <R> R typeCover(Function<String , R> function){ String str = "1235"; return function.apply(str); }
- 普通方法调用:
Integer integer = typeCover(new Function<String, Integer>() { @Override public Integer apply(String s) { return Integer.valueOf(s); } }); System.out.println(integer);
- lambda优化:
Integer int2 = typeCover((String s) -> { return Integer.valueOf(s); }); System.out.println(int2);
- 定义方法:
-
自定义代码3:
- 自定义方法:
public static void foreachArr(IntConsumer consumer){ int[] arr = {1,2,3,4,5,6,7,8,9,10}; for (int i : arr) { consumer.accept(i); } }
- 普通调用:
foreachArr(new IntConsumer() { @Override public void accept(int value) { System.out.println(value); } });
- lambda:
foreachArr(value -> { System.out.println(value); });
- 自定义方法:
1.1.2 lambda表达式省略规则
- 参数类型可以省略;
- 方法体只有一句代码时大括号
return
和唯一的代码的分号可以省略; - 方法只有一个参数时小括号可以省略;
1.2 Stream流式编程
更方便的对集合或数组进行链状流式的操作。
- 使用流对集合数组进行操作时,分为三个过程:
- 创建流;
- 中间操作;
- 终结操作。
1.2.0 类环境搭建
-
Author
实体类@Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode public class Author implements Comparable<Author>{ private Long id; private String name; private Integer age; private String intro; private List<Book> books; @Override public int compareTo(Author o) { return o.getAge() - this.getAge(); } }
-
Book
实体类@Data @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode public class Book { private Long id; private String name; private String category; private Integer score; private String intro; }
-
构建数据工具类
public class CreateDataUtil { public static List<Author> getAuthors() { //数据初始化 Author author = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null); Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null); Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null); Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null); //书籍列表 List<Book> books1 = new ArrayList<>(); List<Book> books2 = new ArrayList<>(); List<Book> books3 = new ArrayList<>(); books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨")); books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理")); books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头")); books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头")); books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解")); books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容")); books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?")); books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?")); author.setBooks(books1); author2.setBooks(books2); author3.setBooks(books3); author4.setBooks(books3); return new ArrayList<>(Arrays.asList(author,author2,author3,author4)); } }
1.2.1 创建流
-
单列集合:直接调用
stream()
方法即可。/** * 单列集合创建流 * @return Stream */ static Stream<Integer> singleColl(){ List<Integer> list = new ArrayList<>(); list.add(1); Set<Integer> set = new LinkedHashSet<>(); set.add(1); return (Math.random() * 10) % 2 == 0 ? list.stream() : set.stream(); }
-
数组:可以使用
Arrays.stream(arr)
或者Stream.of(arr)
来创建。/** * 数组创建流对象 * @return Stream */ static Stream<Integer> ArrColl(){ Integer[] arr = {1,2,3,4}; return (Math.random() * 10) % 2 == 0 ? Arrays.stream(arr) : Stream.of(arr); }
-
多列集合:需要先转为单列集合再创建流:
/** * 多列集合创建流对象 */ static void doubleColl(){ Map<String , Integer> map = new HashMap<>(); map.put("a",1); map.put("b",2); map.put("c",3); // 转成单行集合再转成stream Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream(); }
1.2.2 中间操作
1.2.2.1 filter
对流中元素进行过滤,符合过滤条件的才能继续留在流中。
/**
* 演示流中filter,输出所有大于十八岁的作家名字。
*/
static void filter(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.filter(author -> author.getAge() < 18)
.forEach(author -> System.out.println(author.getName()));
}
1.2.2.2 map
把流中元素进行计算或转换。
-
转换类型:
/** * 演示流中map,获取作家的名称并转为String后打印 */ static void map(){ List<Author> authors = CreateDataUtil.getAuthors(); authors.stream() .map(author -> author.getName()) .forEach(author -> System.out.println(author + "_" + author.getClass().getName()) ); }
-
计算:先转换类型,再进行计算。
/** * 使用map将所有的作家年龄加10,并输出 */ static void mapOfCount(){ List<Author> authors = CreateDataUtil.getAuthors(); authors.stream() .map(author -> author.getAge()) .map(age -> age + 10) .forEach(age -> System.out.println(age + "_" + age.getClass().getName()) ); }
1.2.2.3 distinct
去除流中相同元素,依赖的是对象的
equals()
方法,需要重写当前对象的该方法。
/**
* 使用distinct去重打印打印作家信息
*/
static void distinct(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.distinct()
.forEach(author -> System.out.println(author));
}
1.2.2.4 sorted
对流中元素进行排序。
-
空参:被比较的元素需要实现
Comparable
接口/** * 空参 sorted() : * 按年龄进行降序排序,且去重 * 被排序的元素需要实现compare接口 */ static void sorted(){ List<Author> authors = CreateDataUtil.getAuthors(); authors.stream() .distinct() .sorted() .forEach(author -> System.out.println(author.getAge())); }
-
有参sorted:
/** * 有参sorted */ static void sorted2(){ List<Author> authors = CreateDataUtil.getAuthors(); authors.stream() .distinct() .sorted((a1,a2) -> a2.getAge() - a1.getAge()) .forEach(author -> System.out.println(author.getAge())); }
1.2.2.5 limit
限制流的最大长度,超出部分抛弃。
/**
* limit
*/
static void limit(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.distinct()
.sorted((a1,a2) -> a2.getAge() - a1.getAge())
.limit(2)
.forEach(author -> System.out.println(author.getAge()));
}
1.2.2.6 skip
跳过流中的前n个元素,返回剩下的元素。
/**
* 使用skip打印流中除了最大年另外的其它作家,重复,且按年龄降序
*/
static void skip(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.distinct()
.sorted((a1,a2) -> a2.getAge() - a1.getAge())
.skip(1)
.forEach(author -> System.out.println(author.getAge()));
}
1.2.2.7 flatMap
把一个对象转换成多个对象作为流中的元素。
- 打印图书信息
/**
* 打印当前图书所有数据,且去重
*/
static void flatMap(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
}
-
图书分类
/** * 打印图书的所有分类,且去重,不能以逗号分割。 */ static void flatMap2(){ List<Author> authors = CreateDataUtil.getAuthors(); authors.stream() .flatMap(author -> author.getBooks().stream()) .flatMap(book -> Arrays.stream(book.getCategory().split(","))) .distinct() .forEach(category -> System.out.println(category)); }
1.2.3 终结操作
1.2.3.1 forEach
遍历流中元素, 可以传入指定参数进行操作。
/**
* 打印流中元素,且去重
*/
static void forEach(){
List<Author> authors = CreateDataUtil.getAuthors();
authors.stream()
.distinct()
.forEach(author -> System.out.println(author.getName()));
}
1.2.3.2 count
获取流中元素的个数。
/**
* 获取图书的数目
*/
static void count(){
List<Author> authors = CreateDataUtil.getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
}
1.2.3.3 max & min
求流中的最值。
-
求图书score最高分
/** * 获取数据的最高分 */ static void max(){ List<Author> authors = CreateDataUtil.getAuthors(); Optional<Integer> count = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getScore()) .max((b1,b2) -> b1 - b2); System.out.println(count.get()); }
-
求图书score最低分
/** * 获取数据的最低分 */ static void min(){ List<Author> authors = CreateDataUtil.getAuthors(); Optional<Integer> count = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getScore()) .min((b1,b2) -> b1 - b2); System.out.println(count.get()); }
1.2.3.4 collect
将流中数据转换成集合。
-
转为
List
/** * 返回一个存放所有作者名字的集合 * @return collect */ static List<String> namesByCollect(){ List<Author> authors = CreateDataUtil.getAuthors(); List<String> collect = authors.stream() .map(author -> author.getName()) .collect(Collectors.toList()); System.out.println(collect); return collect; }
-
转为
Set
/** * 返回一个存放所有书名的集合 * @return collect */ static Set<Book> booksByCollect(){ List<Author> authors = CreateDataUtil.getAuthors(); Set<Book> collect = authors.stream() .flatMap(author -> author.getBooks().stream()) .collect(Collectors.toSet()); System.out.println(collect); return collect; }
-
转为
Map
/** * 返回一个map: * k - 作者名 * v - 图书集合 * @return collect */ static Map<String, List<Book>> infoByCollect(){ List<Author> authors = CreateDataUtil.getAuthors(); Map<String, List<Book>> collect = authors.stream() .distinct() .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); return collect; }
1.2.3.5 查找与匹配
-
anyMatch
:判断是否存在符合匹配条件的元素,返回boolean。* 判断是否存在29岁以上的作家 * @return boolean */ static boolean anyMatch(){ List<Author> authors = CreateDataUtil.getAuthors(); boolean b = authors.stream() .anyMatch(author -> author.getAge() > 29); System.out.println(b); return b; }
-
allMatch
:判断是否都符合匹配条件的元素,返回boolean。/** * 判断是否所有作家都是成年人 * @return boolean */ static boolean allMatch(){ List<Author> authors = CreateDataUtil.getAuthors(); boolean b = authors.stream() .allMatch(author -> author.getAge() >= 18); System.out.println(b); return b; }
-
noneMatch
:判断是否都不符合匹配条件的元素,返回boolean。/** * 判断是否所有作家都 没有 超过一百岁 * @return boolean */ static boolean noneMatch(){ List<Author> authors = CreateDataUtil.getAuthors(); boolean b = authors.stream() .noneMatch(author -> author.getAge() > 100); System.out.println(b); return b; }
-
findAny
:获取流中任意一个元素。/** * 获取年龄大于十八的任意一个元素 */ static void findAny(){ List<Author> authors = CreateDataUtil.getAuthors(); Optional<Author> any = authors.stream() .filter(author -> author.getAge() > 18) .findAny(); System.out.println(any.get()); }
-
findFirst
:获取流中第一个元素。/** * 获取年龄最小的元素 */ static void findFirst(){ List<Author> authors = CreateDataUtil.getAuthors(); Optional<Author> any = authors.stream() .sorted((o1, o2) -> o1.getAge() - o2.getAge()) .findFirst(); System.out.println(any.get()); }
1.2.3.6 reduce - 归并
将流中的数据按照指定的计算方式计算出结果。
就是把stream中的元素组合起来,可以传入一个初始值,按照计算方式依次拿流中的元素和在初始化值的基础上进行计算,计算结果再和后面的元素计算。
-
计算全部作者的年龄和
/** * 使用reduce求出所有作者年龄的和 * @return age */ static int reduceAdd(){ List<Author> authors = CreateDataUtil.getAuthors(); Integer reduce = authors.stream() .distinct() .map(author -> author.getAge()) .reduce(0, (result, element) -> result + element); System.out.println(reduce); return reduce; }
-
获取最大年龄作者
/** * 使用reduce求出所有最大作者年龄 * @return age */ static int reduceMaxAge(){ List<Author> authors = CreateDataUtil.getAuthors(); Integer reduce = authors.stream() .distinct() .map(author -> author.getAge()) .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result); System.out.println(reduce); return reduce; }
-
获取最小年龄作者
/** * 使用reduce求出所有最小作者年龄 * @return age */ static int reduceMinAge(){ List<Author> authors = CreateDataUtil.getAuthors(); Integer reduce = authors.stream() .distinct() .map(author -> author.getAge()) .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result); System.out.println(reduce); return reduce; }
1.2.4 注意事项
- 惰性求值:如果没有终结操作,没有中间操作不会执行;
- 一次性的:一旦一个流对象经过一个终结操作后,这个流不能再被使用;
- 不会影响源数据。