通过下面代码,显然我们清晰的看到使用Stream流更为方便,而使用普通的集合遍历就有些复杂。
public class Test01 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("张无忌");
list1.add("周正若");
list1.add("赵斌");
list1.add("张强");
list1.add("张三丰");
// Stream流
list1.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3)
.forEach(name -> System.out.println(name));
// 张无忌
// 张三丰
// 1.把所有“张”姓开头元素存储到新集合
ArrayList<String> list2 = new ArrayList<>();
for (String name : list1) {
if (name.startsWith("张")) {
list2.add(name);
}
}
System.out.println(list2); // [张无忌, 张强, 张三丰]
// 2.把所有“张”姓开头且长度为3的元素存储到新集合
ArrayList<String> list3 = new ArrayList<>();
for (String name : list2) {
if (name.length() == 3) {
list3.add(name);
}
}
System.out.println(list3); // [张无忌, 张三丰]
}
}
二、 Stream流概述
例如上面的小例子,Stream流的思想如下:
Stream流的作用就是:
三、Stream流的使用步骤
结合了Lambda表达式,简化集合、数字的操作。
- 先得到一条Stream流(流水线),并把数据放上去。
- 使用中间方法对流水线上的数据进行操作。
- 使用终结方法对流水线上的数据进行操作。
过滤、转换 | 中间方法 | 方法调用完毕之后,还可以调用其他方法 |
---|---|---|
统计、打印 | 终结方法 | 最后一步,调用完毕之后,不能调用其他方法 |
1. 获取Stream流
获取方式 | 方法名 | 说明 |
---|---|---|
单列集合 | default Stream stream() | Collection中的默认方法 |
双列集合 | 无 | 无法直接使用stream流,需要通过keySet()或者entrySet()变成单列集合 |
数组 | public static Stream stream(T[ ] array) | Arrays工具类中的静态方法 |
一堆零散数据 | public static Stream of(T… values) | stream接口中的静态方法 |
1.1 单列集合
public class StreamTest {
public static void main(String[] args) {
//单列集合获取Stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "a","b","c","d","e");
//获取到一个流水线,并把集合中的数据方法流水线上
//Stream<String> stream1 = list.stream();
//使用终结方法打印流水线上数据
//stream1.forEach( s ->System.out.println(s) );
list.stream().forEach(s -> System.out.println(s));
}
}
1.2 双列集合
public class StreamTest {
public static void main(String[] args) {
//双列集合获取Stream流
//1. 创建双列集合
HashMap<String, Integer> hm = new HashMap<>();
//2. 添加数据
hm.put("aaa", 111);
hm.put("bbb", 222);
hm.put("ccc", 333);
//3.1 获取Stream流方法一: keySet()
//键
hm.keySet().stream().forEach(s -> System.out.println(s));
//3.2 获取Stream流方法二:entrySet()
//键值对
hm.entrySet().stream().forEach(s -> System.out.println(s));
}
}
1.3 数组
Stream接口中静态方法of的细节:
- 方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组。
- 但是数组必须是引用数据类型。
- 如果传递的是基本数据类型,是会把整个数组相当做一个元素,放到一个stream流当中。
public class StreamTest {
public static void main(String[] args) {
//数组获取Stream流
//1.创建基本数据类型数组
int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
//获取stream
Arrays.stream(arr1).forEach(s -> System.out.println(s));
//2.创建引用数据类型数组
String[] arr2 = {"a","b","c"};
//获取stream
Arrays.stream(arr2).forEach(s -> System.out.println(s));
//方式是错误的!!!
//Stream接口中静态方法of的细节
//方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组
//但是数组必须是引用数据类型
//如果传递的是基本数据类型,是会把整个数组相当做一个元素,放到一个stream流当中
Stream.of(arr2).forEach(s -> System.out.println(s));
Stream.of(arr1).forEach(s -> System.out.println(s)); //[I@1b28cdfa
}
}
1.4 零散数据
细节: 一堆零散数据需要是相同的数据类型。
public class StreamTest {
public static void main(String[] args) {
//零散数据获取Stream流
//基本数据类型
Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
//引用数据类型
Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
}
}
2. Stream流的中间方法
方法名称 | 说明 |
---|---|
Stream filter ( Predicate<? super T> predicate ) | 过滤 |
Stream filter ( Predicate<? super T> predicate ) | 获取前几个元素 |
Stream skip ( long n ) | 跳过前几个元素 |
Stream distinct ( ) | 元素去重,依赖(hashCode和equals方法) |
static Stream concat ( Stream a , Stream b ) | 合并a和b两个流为一个流 |
Stream map ( Function<T ,R> mapper ) | 转换流中的数据类型 |
注意一:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程。
注意二:修改Stream流中的数据,不会影响原来集合或者数组中的数据。
public class StreamTest01 {
public static void main(String[] args) {
//1.过滤:把开头的留下,其余数据过滤不要
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三","李四","王五","赵六","张七");
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "张三","李四","王五","赵六","张三");
ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3, "孙七","钱八");
ArrayList<String> list4 = new ArrayList<>();
Collections.addAll(list2, "张三-23","李四-24","王五-25");
list.stream().filter(new Predicate<String>() {
//匿名内部类太麻烦 需要缩写
@Override
public boolean test(String s) {
//如果返回值为true,表示当前数据留下
//如果返回值为false,表示当前数据舍弃
return s.startsWith("张");
}
}).forEach(s -> System.out.println(s)); //张三 张七
list.stream()
.filter(s -> s.startsWith("张"))
.forEach(s -> System.out.println(s));
//2. 获取前几个元素
list.stream()
.limit(3)
.forEach(s -> System.out.println(s)); //张三 李四 王五
//3. 跳过
list.stream()
.skip(4)
.forEach(s -> System.out.println(s)); //张七
//4.去重
list2.stream()
.distinct()
.forEach(s -> System.out.println(s)); //张三 李四 王五 赵六
//5. 合并
Stream.concat(list2.stream(), list3.stream())
.forEach(s -> System.out.println(s));
//6.转换数据类型
//只能获取集合里面的年龄并打印
//第一个类型:流中原本的数据类型
//第二个类型:将要转变成为的数据类型
list4.stream().map(new Function<String,Integer>() {
@Override
//apply: 依次表示流中的每一盒数据
//返回值:表示转化之前的数据
public Integer apply(String s) {
String[] arr = s.split("-");
String ageString = arr[1];
int age = Integer.parseInt(ageString);
return age;
}
}).forEach(s -> System.out.println(s));
list.stream()
.map(s ->Integer.parseInt(s.split("-")[1]))
.forEach(s -> System.out.println(s));
}
}
3. Stream流的终结方法
方法名称 | 说明 |
---|---|
void forEach ( Consumer action ) | 遍历 |
long count ( ) | 统计 |
toArray ( ) | 收集流中的数据,放到数组中 |
collect ( Collector collector ) | 收集流中的数据,放到集合中 |
public class StreamTest02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张三", "李四", "王五", "赵六");
// 遍历
// Consumer的泛型:表示流中的数据类型
// accept方法的形参s:依次表示流中的每一个数据
//
list.stream().forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
list.stream().forEach(s -> System.out.println(s)); // 张三 李四 王五 赵六
// 统计
long count = list.stream().count();
System.out.println(count); // 4
// 收集数据放进数组
Object[] arr1 = list.stream().toArray();
System.out.println(Arrays.toString(arr1)); // [张三, 李四, 王五, 赵六]
// 指定数据类型
// Infunction的泛型:具体类型的数组
// apply中形参:流中数据的个数,要跟数组长度一致
// apply的返回值:具体类型的数组
String[] arr2 = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
// toArray方法中的参数:只是创建一个指定类型的数组
// toArray底层: 会此意得到流中的每一个数据,并把数据放到数组中
// toArray的返回值:是一个装着流里面所有数据的数组
System.out.println(Arrays.toString(arr2));
// lambda表达式
String[] arr3 = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(arr3));
}
}
下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:
![HTML、CSS部分截图](https://img-blog.csdnimg.cn/img_convert/2bb6b442a4432372fe5b9ccea2ad93d0.png)
### 进阶阶段
进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。
JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。
我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。
然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。
**1、JavaScript 和 ES6**
在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。
![JavaScript部分截图](https://img-blog.csdnimg.cn/img_convert/cac778dc45492a41e2f3e7cd6b0134e5.png)
**2、前端框架**
前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。
以 Vue 为例,我整理了如下的面试题。
![Vue部分截图](https://img-blog.csdnimg.cn/img_convert/c6738a80c94640db83f7ffbf487ac5f0.png)