Java8新特性笔记--波哥带你学JAVA--Stream Api
欢迎大家加入CSDN开发云
1.集合处理数据的弊端
当我在需要对集合中的元素进行操作的时候,除了必须的添加删除获取外,最典型的操作就是集合遍历
public class Demo01StreamApi {
public static void main(String[] args) {
// 定义一个集合
List<String> list = Arrays.asList("张三","张三丰","成龙","周星驰");
// 1.获取所有姓张的信息
List<String> list1 = new ArrayList<>();
for (String s : list) {
if (s.startsWith("张")){
list1.add(s);
}
}
// 2.获取名称长度为3的用户
List<String> list2 = new ArrayList<>();
for (String s : list1) {
if (s.length() == 3){
list2.add(s);
}
}
// 3.输出所有用户信息 张姓且三个字
for (String s: list2) {
System.out.println(s);
}
}
}
上面的代码针对于我们不同的需求总是一字字的循环循环,这是我们希望有更加高效的处理方式,
我们可以通过jdk8中提供的Stream Api来解决这个问题。
Stream更加优雅的解决方案:
public class Demo02StreamApi {
public static void main(String[] args) {
// 定义一个集合
List<String> list = Arrays.asList("张三","张三丰","成龙","周星驰");
// 1.获取所有姓张的信息
// 2.获取名称长度为3的用户
// 3.输出所有用户信息 张姓且三个字
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
System.out.println("------------------------------------------------");
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length() == 3)
.forEach(System.out::println);
}
}
上面的StreamAPI代码的含义:获取流,过滤张,过滤字长,逐一打印。代码相比于上面的案例更加简洁直观。
2.Stream流的作用
Stream API能让我们快速完成许多复杂的操作,如筛选,切片,映射,查找,去重,统计,匹配和归约。
3.Stream流的获取方式
3.1 根据Collection获取
首先,java.util.Collection接口中加入了default方法stream,也就是说Collection接口下的所有实现都可以
通过stream方法来获取Stream流对象
public class Demo03StreamApi {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.stream();
Set<String> set = new HashSet<>();
set.stream();
Vector vector = new Vector();
vector.stream();
}
}
但是Map接口没有实现Collection接口,这时该怎么办呢? 这是可以根据Map获取对应的key value的集合。
public class Demo04StreamApi {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
Stream<String> stream1 = map.keySet().stream();
Stream<Object> stream2 = map.values().stream();
Stream<Map.Entry<String, Object>> stream = map.entrySet().stream();
}
}
3.2 通过Stream的of方法
在实际开发中我们不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所以Stream接口中
提供了静态方法of
public class Demo05StreamApi {
public static void main(String[] args) {
Stream<String> a1 = Stream.of("a1", "a2", "a3", "a4");
String[] arr1 = {"aa","b","cc"};
Stream<String> arr11 = Stream.of(arr1);
Integer[] arr2 = {1,2,3,4};
Stream<Integer> arr21 = Stream.of(arr2);
arr21.forEach(System.out::println);
// 注:基本数据类型的数组是不行的 会将数组数据看成一个整体
int[] arr3 = {1,2,3,4};
Stream.of(arr3).forEach(System.out::println);
}
}
4.Stream常用方法介绍
终结方法:返回值类型不再是Sream类型的方法,不再支持链式调用,包括count和foreach。
非终结方法:返回值类型仍然是Stream类型的方法,支持链式调用。
Stream注意事项
1.Stream只能操作一次
2.Stream方法返回的是一个新的流
3.Stream不调用终结方法,中间的操作不会执行,必须以终结方法结束
4.1 forEach
foreach用来遍历流中的数据的
void forEach(Consumer<? super T> action);
该方法接受一个Consumer接口,会将每一个流元素交给函数处理
public class Demo07StreamApiForeach {
public static void main(String[] args) {
Stream.of("a1", "a2", "a3")
.forEach(System.out::println);
}
}
4.2 count
Stream流中的count方法用来统计其中的元素个数的
long count();
该方法返回一个long值,代表元素个数。
public class Demo08StreamApiCount {
public static void main(String[] args) {
long count = Stream.of("a1", "a2", "a3").count();
System.out.println(count);
}
}
4.3 filter
filter方法的作用是用来过滤数据的,返回符合条件的数据
可以通过filter方法讲一个流转换成另一个子集流
Stream<T> filter(Predicate<? super T> predicate);
该接口接受一个Predicate函数式接口参数作为筛选条件
public class Demo09StreamApiFilter {
public static void main(String[] args) {
Stream.of("a1", "a2", "a3","bb","cc","dd").filter(s -> s.contains("a"))
.forEach(System.out::println);
}
}
4.4 limit
limit方法可以对流进行截取处理,支取前n个数据
Stream<T> limit(long maxSize);
参数是一个long类型的数值,如果集合长度大于参数就进行截取,否则不操作:
public class Demo10StreamApiLimit {
public static void main(String[] args) {
Stream.of("a1", "a2", "a3", "bb", "cc", "aa", "dd").limit(5)
.forEach(System.out::println);
}
}
4.5 skip
如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流:
public class Demo11StreamApiSkip {
public static void main(String[] args) {
Stream.of("a1", "a2", "a3","bb","cc","aa","dd").skip(3)
.forEach(System.out::println);
}
}
4.6 map
如果我们需要将流中的元素映射到另一个流中可以使用map方法;
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据
public class Demo12StreamApiMap {
public static void main(String[] args) {
Stream.of("1", "2", "3","4","5","6","7")
//.map(s -> Integer.parseInt(s))
.map(Integer::parseInt)
.forEach(System.out::println);
}
}
4.7 sorted
如果需要将数据排序,可以使用sorted方法:
Stream<T> sorted();
在使用的时候可以根据自然规则排序,也可以通过比较来指定对应的排序规则
public class Demo13StreamApiSorted {
public static void main(String[] args) {
Stream.of("1", "9", "3","4","22","6","7")
.map(Integer::parseInt)
//.sorted() //根据数据的自然顺序排序
.sorted((o1,o2)->o2-o1) //根据比较指定排序规则
//.sorted(Integer::compareTo)
.forEach(System.out::println);
}
}
4.8 distinct
如果要去掉重复的数据,可以使用distinct方法:
Stream<T> distinct();
public class Dmo14StreamApiDistinct {
public static void main(String[] args) {
Stream.of("1", "9", "3","4","3","6","7")
.distinct() //去掉重复数据
.forEach(System.out::println);
System.out.println("---------------------------------");
Stream.of(
new Person("张三",18,198),
new Person("李四",22,199),
new Person("张三",18,167)
).distinct()
.forEach(System.out::println);
}
}
Stream流中的 方法对于基本数据类型是可以直接去重的,但是对于自定义类型,我们是需要重写 hashCode和equals方法来移除重复元素
4.9 match
`如果需要判断数据是否匹配指定的条件,可以使用match相关的方法
boolean anyMatch(Predicate<? super T> predicate);// 元素是否有任意一个满足条件
boolean allMatch(Predicate<? super T> predicate);// 元素是否都满足条件
boolean noneMatch(Predicate<? super T> predicate);// 元素是否都不满足条件
使用
public class Demo15StreamApiMatch {
public static void main(String[] args) {
boolean b = Stream.of("1", "9", "3", "4", "3", "6", "7")
.map(Integer::parseInt)
//.allMatch(s -> s > 0)
//.anyMatch(s -> s > 4)
.noneMatch(s-> s > 4);
System.out.println(b);
}
}
注意:match也是终结方法
4.10 find
如果我们需要找到某些元素,可以使用find方法来实现
Optional<T> findFirst();
Optional<T> findAny();
使用
public class Demo16StreamApiFind {
public static void main(String[] args) {
Optional<String> first = Stream.of("1", "9", "3", "4", "3", "6", "7").findFirst();
System.out.println(first.get());
Optional<String> any = Stream.of("1", "9", "3", "4", "3", "6", "7").findAny();
System.out.println(any.get());
}
}
4.11 max和min
如果我们想要获取最大值和最小值没那么可以使用max和min方法
Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);
使用
public class Demo17StreamApiMaxMin {
public static void main(String[] args) {
Optional<Integer> first = Stream.of("1", "9", "3", "4", "3", "6", "7")
.map(Integer::parseInt)
.max((o1,o2)->o1-o2);
System.out.println(first.get());
Optional<Integer> any = Stream.of("1", "9", "3", "4", "3", "6", "7")
.map(Integer::parseInt)
.min(((o1, o2) -> o1-o2));
System.out.println(any.get());
}
}
4.12 reduce
如果需要将所有数据归纳得到一个数据,使用reduce方法
T reduce(T identity, BinaryOperator<T> accumulator);
使用
public class Demo18StreamApiReduce {
public static void main(String[] args) {
Integer total = Stream.of(4, 5, 3, 9)
// identity是默认值
// 第一次的时候会将默认值赋给x
// 之后每次会将上一次的操作结果赋值给x y就是每次从数据中获取的元素
.reduce(0, (x, y) -> {
System.out.println("x="+x+",y="+y);
return x + y;
});
System.out.println(total);
// 获取最大值
Integer max = Stream.of(4, 5, 3, 9)
.reduce(0, (x, y) -> {
return x > y ? x : y;
});
System.out.println(max);
// 获取最小值
Optional<Integer> reduce2 = Stream.of(4, 5, 3, 9)
.reduce((x, y) -> {
return x < y ? x : y;
});
System.out.println(reduce2.get());
}
}
4.13 map和reduce的组合
在实际开发中,我们经常会将map和reduce组合使用
public class Demo19StreamApiMapReduce {
public static void main(String[] args) {
//求年龄总和
Integer sumAge = Stream.of(
new Person("张三", 18, 198),
new Person("李四", 22, 199),
new Person("张三", 18, 167),
new Person("赵六", 19, 176),
new Person("张三", 33, 180)
).map(Person::getAge)
.reduce(0, Integer::sum);
System.out.println(sumAge);
// 求出年龄最大值
Integer maxAge = Stream.of(
new Person("张三", 18, 198),
new Person("李四", 22, 199),
new Person("张三", 18, 167),
new Person("赵六", 19, 176),
new Person("张三", 33, 180)
).map(Person::getAge)
.reduce(0, Math::max);
System.out.println(maxAge);
//统计 字符 a 出现的次数
Integer count = Stream.of("a", "b", "c", "d", "a", "c", "a")
.map(s -> "a".equals(s) ? 1 : 0)
.reduce(0, Integer::sum);
System.out.println(count);
}
}
4.14 mapToInt
如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现
public class Demo20StreamApiMapToInt {
public static void main(String[] args) {
// Integer占用的内存比int多很多,在stream流操作中会自动拆装箱操作
Integer arr[] = {1,2,3,4,5};
Stream.of(arr)
.filter(integer -> integer > 0)
.forEach(System.out::println);
// 为了提高程序代码的效率, 我们可以现将流中Integer数据转换为int数据,然后操作
Integer arr2[] = {1,2,3,4,5,7,9};
Stream.of(arr2)
.mapToInt(Integer::intValue)
.filter(i -> i > 4)
.forEach(System.out::println);
}
}
4.15 concat
如果有两个流希望合并成为一个流,那么可以使用Stream接口的静态方法concat
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b);
@SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
}
使用:
public class Demo21StreamApiConcat {
public static void main(String[] args) {
Stream<String> stream1 = Stream.of("a", "b", "c");
Stream<String> stream2 = Stream.of("x", "y", "z");
// 通过concat方法将两个流合并成一个新的流
Stream.concat(stream1,stream2)
.forEach(System.out::println);
}
}
4.16 综合案例
public class Demo22StreamApiTest {
/**
* @methodName main
* @description
* 定义两个集合,然后再集合中存储多个用户名称,然后完成如下操作:
* 1.第一个队伍只保留姓名长度为3的成员
* 2.第一个队伍筛选后只要前三个
* 3.第二个队伍只要姓张的成员
* 4.第二个队伍筛选之后不要前两个人
* 5.将两个队伍合并成一个队伍
* 6.根据姓名创建Person对象
* 7.打印整个队伍的Person信息
* @author FredHe
* @param args
* @return
* @since 2022/4/23 18:09
*/
public static void main(String[] args) {
List<String> list1 = Arrays.asList("迪丽热巴","宋远桥","苏星河","老子","庄子","孙子","洪七公");
List<String> list2 = Arrays.asList("古力娜扎","张无忌","张三丰","赵丽颖","张二狗","张天爱","张三");
// 1.第一个队伍只保留姓名长度为3的成员
// 2.第一个队伍筛选后只要前三个
Stream<String> stream1 = list1.stream().filter(s -> s.length() == 3).limit(3);
// 3.第二个队伍只要姓张的成员
// 4.第二个队伍筛选之后不要前两个人
Stream<String> stream2 = list2.stream().filter(s -> s.startsWith("张")).skip(2);
// 5.将两个队伍合并成一个队伍
Stream<String> stream3 = Stream.concat(stream1, stream2);
// 6.根据姓名创建Person对象
// 7.打印整个队伍的Person信息
stream3.map(Person::new).forEach(System.out::println);
}
}
输出结果
Person(name=宋远桥, age=null, height=null)
Person(name=苏星河, age=null, height=null)
Person(name=洪七公, age=null, height=null)
Person(name=张二狗, age=null, height=null)
Person(name=张天爱, age=null, height=null)
Person(name=张三, age=null, height=null)
未完待续
本人代码笔记gitee地址:https://gitee.com/FredHeYuTong/learn-java8