1. lambda表达式
即允许将函数作为参数传递进方法中。可以替代匿名内部类的编写
新手一开始不能直接写出lambda表达式,我们可以先用Idea的提示写出匿名内部类,匿名内部类比较好看懂,写好之后再用Idea的提示将匿名内部类转为lambda表达式,熟练之后我们就可以独立写出lambda表达式了。
2. Stream流
最后必须有终结方法的调用,否则中间方法都不会执行
因为Stream流是惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行
可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
先创建好author集合方便后边使用
private static List<Author> getAuthor(){
//数据初始化
Author author = new Author(1L,"程长新",33,"一个从菜刀中明悟哲理的祖安人",null);
Author author2 = new Author(2L,"李丽云",16,"狂风也追逐不上他的思考速度",null);
Author author5 = 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,"一个人不能死在同一把刀下","个人成长,爱情",88,"用一把刀划分了爱恨"));
books2.add(new Book(3L,"那风吹不到的地方","哲学",88,"带你用思维去领略世界的尽头"));
books2.add(new Book(3L,"那风吹不到的地方","哲学",88,"带你用思维去领略世界的尽头"));
books2.add(new Book(4L,"吹或不吹","爱情,个人传记",88,"一个哲学家的恋爱观注定很难把他"));
books3.add(new Book(5L,"你的剑就是我的剑","爱情",88,"无法想象一个武者能对他的伴侣这么"));
books3.add(new Book(6L,"风与剑","个人传记",88,"两个哲学家灵魂和肉体的碰撞会激起这么"));
books3.add(new Book(6L,"风与剑","个人传记",88,"两个哲学家灵魂和肉体的碰撞会激起这么"));
author.setBooks(books1);
author2.setBooks(books2);
author3.setBooks(books3);
author4.setBooks(books3);
author5.setBooks(books1);
List<Author> authorList = new ArrayList<>(Arrays.asList(author,author2,author3,author4,author5));
return authorList;
}
1. 创建流
1.1 单列集合创建流
直接集合对象.stream()
就可以返回Stream对象了
比如List对象
List<Author> authorList = getAuthor();
Stream<Author> stream = authorList.stream();
1.2 数组创建流
Arrays.stream(数组)
int[] arr = {1,2,3,4,5};
IntStream stream = Arrays.stream(arr);
stream
.filter(number >3)
.forEach(number ->System.out.print(number));
//结果输出是4 5
1.3 双列集合创建流
Map即双列集合,需要转换为单列集合才可以创建流
Map<String, Integer> map = new HashMap<>();
map.put("程长新",12);
map.put("李丽云",14);
map.put("程杨",16);
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
Stream<Map.Entry<String, Integer>> stream = entrySet.stream();
stream
.filter(entry -> entry.getValue()<15)
.forEach(entry -> System.out.println(entry.getKey()+"---"+entry.getValue()));
//结果输出是程长新---12 李丽去---14
2. 常用中间操作
2.1 filter(变量 -> 判断条件)
过滤,返回boolean,判断每一条流数据是否符合条件,如果返回false则去掉该条数据。
即过滤掉流中不符合条件的数据
2.2 forEach(变量 -> 操作)
遍历流中的每一条数据,进行操作
2.3 map(变量 -> 操作)与flatMap()
都可以对流中的数据进行计算或转换
map只能将流中的一条对象转换为另一个对象来作为流中的元素,而flatMap可以将一个对象转换为多个对象再作为流中的元素(因为flatMap操作的返回结果也是stream,即可以将一个对象转换为流后返回)
为了减少后期对基本数据类型操作的自动拆装箱时间,JDK也提供了直接将数据转化的基本数据类型的map方法mapToInt()、mapToLang()、maoToDouble()以及对应的flatMap的方法
//将名字长度大于7的都转为大写输出
List<String> list = Arrays.asList("ChengChangxin", "LiLiyun","ChengYang");
list.stream()
.filter(name -> name.length()>7)
.map(name -> name.toUpperCase())//对流中的数据进行操作后返回
.forEach(name -> System.out.println(name));
//flatMap()
//将每个作者的书都打印出来并去重
List<Author> authors = getAuthor();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
//加深flatMap理解,将所有书的所属分类打印出来,一个一个打
//打印所有分类并去重,一个一个打,不能出现逗号
System.out.println("所有分类============");
authors.stream()
.flatMap(author -> author.getBooks().stream())//先拿到每个作者的所有书
.distinct()//对书去重
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))//拿到分类后按逗号分隔为数组再转为stream返回
.distinct()//对分类去重
.forEach(category -> System.out.println(category));
2.4 distinct()
对流中的数据去重
distinct依赖的是object的equals方法来判断是否是相同对象的
所以如果需要的话要重写equals方法,因为equal方法只有在对象地址相同时才是相同对象,如果我们想对象值相同即为相同对象的话就要重写equal方法
2.5 sorted()
sorted()有两个重载方法
-
一是无参的方法
无参方法需要流对象自己已经实现Comparable接口,定义好比较规则
-
二是有参的方法
传递Comparable匿名内部类自己定义比较规则
List<String> list = Arrays.asList("ChengChangxin", "LiLiyun","ChengYang");
list.stream()
.sorted()//list对象已经实现了comparable接口,所以可以直接调用无参的sorted方法
.forEach(name -> System.out.println(name));
List<Author> authors = getAuthor();
authors.stream()
.sorted()//手动为Author类实现comparable接口
.forEach(author -> System.out.println(author.getName()+"---"+author.getAge()));
//结果
ChengChangxin
ChengYang
LiLiyun
程长新---33
李丽云---15
易---14
易---14
为Author类实现comparable接口
调用有参的sorted方法
List<Author> authors = getAuthor();
authors.stream()
// .sorted()//手动为Author类实现comparable接口
/*.sorted(new Comparator<Author>() {
@Override
public int compare(Author o1, Author o2) {
return o1.getAge() - o2.getAge();
}
})*/
.sorted((o1,o2) -> o2.getAge() - o1.getAge())
.forEach(author -> System.out.println(author.getName()+"---"+author.getAge()));
//结果
程长新---33
李丽云---16
程杨---15
易---14
易---14
2.6 limit(n)方法
限制stream流中的数据条数,只留下前n条
比如要输出年龄最大的前两个作家。思路是对作家排序后只留下两个
//limit()方法
System.out.println("年龄最大的前两位");
authors.stream()
.sorted((o1,o2) -> o2.getAge() - o1.getAge())
.limit(2)
.forEach(author -> System.out.println(author.getName()+"---"+author.getAge()));
//结果
年龄最大的前两位
程长新---33
李丽云---16
2.7 skip(n)方法
跳过流中的前n条数据,只留下后边的数据
//需求:打印除了年龄最大的其余所有人
List<Author> author = getAuthor();
author.stream()
.distinct()
.sorted()//按年龄降序排
.skip(1)//跳过第一个年龄最大的
.forEach(one -> System.out.println(one.getAge()+"---"+one.getName()));
//author中原来数据
33---程长新
16---李丽云
15---程杨
14---易
//使用skip(1)后的
16---李丽云
15---程杨
14---易
3 常用终结操作
3.1 forEach()
对流中的每个元素进行遍历
3.2 count()
统计流中的元素个数,是long类型的返回值
3.3 max()和min()方法
对流中的元素求最大和最小值,返回optional对象
//获取评分最高的书籍
List<Author> authors = getAuthor();
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println(max.get());
3.4 collect()方法
将流数据收集为集合对象。在collect()中传递Collectors工具类的方法即可
//获取一个存放作者名字的list集合
List<Author> authors = getAuthor();
List<String> nameList = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(nameList);
//获取所有书名的set集合
Set<String> bookSet = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getName())
.collect(Collectors.toSet());
System.out.println(bookSet);
//获取map,键为作者名字,值为book集合
Map<String, List<Book>> authorMap = authors.stream()
.distinct()//因为map键不能重复,所以要对作者去重
.collect(Collectors.toMap(/*map的键*/author -> author.getName(), /*map的值*/author -> author.getBooks()));
System.out.println(authorMap);
3.5 查找和匹配方法
(1)anyMatch()
流中的数据有一条符合条件就返回true,全都不符合则返回false
List<Author> authors = getAuthor();
//看所有作者中是不是有大于20岁的
boolean b = authors.stream()
.anyMatch(new Predicate<Author>() {
@Override
public boolean test(Author author) {
return author.getAge() > 20;
}
});
System.out.println("看所有作者中是不是有大于20岁的: "+b);
(2)allMatch()
流中的所有元素符合条件才返回true
(3)noneMatch()
流中的所有元素都不符合条件才返回true
//看是不是所有作者都不到60岁
List<Author> authors = getAuthor();
boolean b = authors.stream().noneMatch(author -> author.getAge() > 60);
System.out.println("看是不是所有作者都不到60岁: "+b);
(4)findAny()
随便取流中的一条数据
(5)findFirst()
取流中的第一条数据
(6)reduce()归并方法
对流中所有元素进行指定操作之后返回一个值
-
重载方法一
reduce(参数一,参数二)
参数一为初始值 ,它的类型为当前流中数据中类型,参数二为指定操作,最后返回结果类型也是流中数据类型
-
重载方法二
reduce(参数)
不用指定初始值 ,处理过程中会把流中第一条数据作为初始值 ,只指定操作就可以,返回值为optional类型
List<Author> authors = getAuthor();
Integer reduce = authors.stream()
.map(author -> author.getAge())
.reduce(0, (result, age) -> result + age);//第一个参数(0)是初始值,第二个参数((result,age))中的第一个是结果变量,第二个是流中的每一个元素
System.out.println("作家年龄和:"+reduce);
//最大年龄作家
Integer maxAge = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer age) {
return result < age ? age : result;
}
});
System.out.println("用reduce找出年龄最大的作家:"+maxAge);
//最小年龄作家
Integer minAge = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MAX_VALUE, (result, age) -> result < age ? result : age);
System.out.println("用reduce找出年龄最小的作家:"+minAge);
//用一个参数的重载方法进行计算最大年龄
Optional<Integer> max = authors.stream()
.map(author -> author.getAge())
.reduce((result, age) -> result > age ? result : age);
System.out.print("用一个参数的重载方法进行计算最大年龄:");
max.ifPresent(age -> System.out.println(age));
4 并行流
将流数据放到多个线程中进行处理,对处理大批量数据时是友好的。
对象直接调用parallelStream()
方法就可以返回并行流数据
或者调用stream()
获取到流数据再调用parallel()
方法将串行流转换为并行流
peek()
方法是专门用来测试流数据的方法
List<Author> authors = getAuthor();
authors.parallelStream()
.peek(author -> System.out.println(author.getName()+"==="+Thread.currentThread().getName()))
.forEach(author -> System.out.println());
boolean parallel = authors.stream()
.parallel()
.isParallel();
System.out.println(parallel);
//结果,可以看到流数据在多个线程中运行
易===main
程杨===ForkJoinPool.commonPool-worker-2
李丽云===ForkJoinPool.commonPool-worker-1
易===ForkJoinPool.commonPool-worker-1
程长新===ForkJoinPool.commonPool-worker-3
true
3.Optional对象
目的是为了避免空指针异常的出现
1 Optional对象的创建
使用Optional类的静态方法ofNUllable(对象)
即可将对象包装为Optional对象
如果确定对象不为空的话可以直接使用of(对象)
来包装对象,当出现空的时候用empty()
来替代则可以不报错
所以一般都使用ofNullable(对象)
来创建Optional对象,不用关心对象是否为空
private static void optionalCreateTest() {
List<Author> authors = getAuthor();
//用Optional的静态方法ofNullable来包装对象,可以接受空值
Optional<List<Author>> authorsOptional = Optional.ofNullable(null);
Optional<List<Author>> authorsOptional1 = Optional.ofNullable(authors);
//当确定对象不是空值的时候可以用of()直接来包装,但传入null时会报空指针异常
Optional<List<Author>> authorsOptional2 = Optional.of(authors);
// Optional<List<Author>> authorsOptional3 = Optional.of(null);//会报错
//如果确实需要封装空对象,可以使用empty()方法
getAuthorOptional();
}
private static Optional<Author> getAuthorOptional() {
// Author author = new Author(1L,"小小",33,"一个从菜刀中明悟哲理的祖安人",null);
Author author = null;
return author == null ? Optional.empty() : Optional.of(author);
}
2 安全的消费值
调用Optional对象的ifPresent()方法
即对象中有内容时才执行传递的操作
Optional<Author> authorOptional = getAuthorOptional();
authorOptional.ifPresent(author -> System.out.println("作家姓名:"+author.getName()));
3 安全的获取值
如果直接用get()
来获取的话当对象中为null的时候会报错
可以用orElseGet()
方法。如果authorOptional中有值就话返回它的值,如果它是空就返回后边的默认值
Optional<Author> authorOptional = getAuthorOptional();
Author author = authorOptional.orElseGet(() -> new Author(1L,"长新",3,"一个从菜刀中明悟哲理的祖安人",null));
System.out.println(author.getName());
也可以用orElse(直接指定默认值)
,这个方法不用传lambda表达式,直接把默认值作为参数
当值为null时抛出自定义异常orElseThrow()
Optional<Author> authorOptional = getAuthorOptional();
try {
Author result = authorOptional.orElseThrow(() -> new RuntimeException("自定义异常:数据为null"));
} catch (Throwable e) {
e.printStackTrace();
}
//当authorOptional为空时抛出如下异常
//java.lang.RuntimeException: 自定义异常:数据为null
4 过滤filter()
与stream的使用一样
5 判断1isPresent()
判断Optional对象中是否有值,返回boolean
6 map()方法
与Stream的map()方法一样
标签:stream,author,System,特性,authors,println,Java8,out From: https://www.cnblogs.com/ccx-lly/p/16705648.html