文章目录
-
- 1. 一个流的使用例子
- 2. 流简介
- 3. 流的特点
- 4. 流基本操作
-
- 4.1 中间操作
- 4.2 终端操作
- 5. 筛选和切片
-
- 5.1 用谓词筛选
- 5.2 筛选各异的元素
- 5.3 截短流
- 5.4 跳过元素
- 6. 映射
-
- 6.1 对流中每一个元素应用函数
- 6.2 流的扁平化
- 7. 查找和匹配
-
- 7.1 检查谓词是否至少匹配一个元素
- 7.2 检查谓词是否匹配所有元素
- 7.3 查找任意元素
- 7.4 查找第一个元素
- 8. 归约
-
- 8.1 元素求和
- 8.2 最大值和最小值
- 9. 数值流
-
- 9.1 原始类型流特化
- 9.2 数值范围
- 10. 构建流
-
- 10.1 由值创建流
- 10.2 由数组创建流
- 10.3 由文件生成流
- 10.4 由函数生成流:创建无限流
1. 一个流的使用例子
场景:现在有一个菜品集合,需要找出菜品中的卡路里小于400的菜品并且按照卡路里多少进行排序
class Dish{
String name;
int price;
int calories;
public Dish(String name, int price, int calories) {
super();
this.name = name;
this.price = price;
this.calories = calories;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getCalories() {
return calories;
}
public void setCalories(int calories) {
this.calories = calories;
}
@Override
public String toString() {
return "Dish [name=" + name + ", price=" + price + ", calories=" + calories + "]";
}
}
普通方式的实现:
public class StreamDemo {
public static void main(String[] args) {
List<Dish> menu=Arrays.asList(
new Dish("pork",800),
new Dish("beef",700),
new Dish("chicken",400),
new Dish("french fries",530),
new Dish("rice",350),
new Dish("fruit",120),
new Dish("pizza",550));
List<Dish> lowCaloriesDish=new ArrayList<>();
for(Dish d:menu)
{
if(d.getCalories()<400)
lowCaloriesDish.add(d);
}
Collections.sort(lowCaloriesDish,new Comparator<Dish>() {
@Override
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCalories(), o2.getCalories());
}
});
for(Dish d:lowCaloriesDish)
System.out.println(d.getName()+" "+d.getCalories());
}
}
使用流实现:
import java.util.List;
import static java.util.stream.Collectors.toList;
public class StreamDemo {
public static void main(String[] args) {
List<Dish> menu=Arrays.asList(
new Dish("pork",800),
new Dish("beef",700),
new Dish("chicken",400),
new Dish("french fries",530),
new Dish("rice",350),
new Dish("fruit",120),
new Dish("pizza",550));
List<String> lowCaloriesDishName=menu.stream()
.filter(d->d.getCalories()<400)
.sorted((d1,d2)->d1.getCalories()-d2.getCalories())
.map(d->d.getName())
.collect(toList());
for(String name:lowCaloriesDishName)
System.out.println(name);
}
}
2. 流简介
流是从支持数据处理操作的源生成的元素序列
- 元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值
- 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源
- 数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等
- 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大的流水线
- 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的
3. 流的特点
1. 流只能遍历一次
public class StreamDemo {
public static void main(String[] args) {
List<String> title=Arrays.asList("Java","Python","Go");
Stream<String> s=title.stream();
s.forEach(System.out::println);
s.forEach(System.out::println);
}
}
2. 流使用内部迭代
public class StreamDemo {
public static void main(String[] args) {
List<Dish> menu=Arrays.asList(
new Dish("pork",800),
new Dish("beef",700),
new Dish("chicken",400),
new Dish("french fries",530),
new Dish("rice",350),
new Dish("fruit",120),
new Dish("pizza",550));
/*
* 集合使用外部迭代
*/
List<String> names=new ArrayList<>();
Iterator<Dish> iterator=menu.iterator();
while(iterator.hasNext()) {
Dish d=iterator.next();
names.add(d.getName());
}
System.out.println(names);
/*
* 流使用内部迭代
*/
List<String> names2=menu.stream()
.map(Dish::getName)
.collect(toList());
System.out.println(names2);
}
}
4. 流基本操作
4.1 中间操作
List<String> names=menu.stream()
.filter(d->d.getCalories()>400)
.map(d->d.getName())
.limit(3)
.collect(toList());
System.out.println(names);
代码中的filter、map、limit是中间操作
4.2 终端操作
public static void main(String[] args) {
List<Dish> menu=Arrays.asList(
new Dish("pork",800),
new Dish("beef",700),
new Dish("chicken",400),
new Dish("french fries",530),
new Dish("rice",350),
new Dish("fruit",120),
new Dish("pizza",550));
menu.stream().forEach(System.out::println);
}
将流中的数据输出到终端上
5. 筛选和切片
5.1 用谓词筛选
filter:返回一个包括所有符合谓词的元素的流
public static void main(String[] args) {
List<Dish> menu=Arrays.asList(
new Dish("pork",800,false),
new Dish("beef",700,false),
new Dish("chicken",400,false),
new Dish("french fries",530,false),
new Dish("rice",350,false),
new Dish("fruit",120,true),
new Dish("tomato",200,true));
List<Dish> vegetableMenu=menu.stream()
.filter(d->d.isVegetable)//是否是蔬菜
.collect(toList());
System.out.println(vegetableMenu);
}
5.2 筛选各异的元素
distinct():它会返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流
List<Integer> numbers=Arrays.asList(1,2,2,3,4,4,5,7);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.collect(toList());
System.out.println(evenNumbers);//[2, 2, 4, 4]
上面代码在一个集合中寻找偶数,结果中有两个相同的2,两个相同的4
List<Integer> numbers=Arrays.asList(1,2,2,3,4,4,5,7);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.distinct()//distinct保证元素唯一
.collect(toList());
System.out.println(evenNumbers);//[2, 4]
5.3 截短流
limit(n):该方法会返回一个不超过给定长度的流
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.collect(toList());
System.out.println(evenNumbers);//[2, 4, 6, 8]
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.limit(2)
.collect(toList());
System.out.println(evenNumbers);//[2, 4]
5.4 跳过元素
skip方法返回一个扔掉了前n个元素的流。如果流中元素不足n个,则返回一个空流
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.skip(1)//跳过流中的前n个元素
.collect(toList());
System.out.println(evenNumbers);//[4, 6, 8]
6. 映射
6.1 对流中每一个元素应用函数
/*
* 先找出集合中的偶数 再将这些偶数进行平方操作
*/
List<Integer> numbers=Arrays.asList(1,2,3,4,5,6,7,8,9);
List<Integer> evenNumbers=numbers.stream()
.filter(x->x%2==0)//寻找偶数
.map(x->x*x)
.collect(toList());
System.out.println(evenNumbers);//[2,4,6,8]->[4, 16, 36, 64]
6.2 流的扁平化
List<String> words=Arrays.asList("Monday","Tuesday");
List<String> characters=words.stream()
.map(word->word.split(""))//将每个单词转化为一个字符串数组
.flatMap(Arrays::stream)//将每个字符数组扁平化
.collect(toList());
System.out.println(characters);//[M, o, n, d, a, y, T, u, e, s, d, a, y]
7. 查找和匹配
7.1 检查谓词是否至少匹配一个元素
anyMatch方法可以回答“流中是否有一个元素能匹配给定的谓词
List<Integer> numbers=Arrays.asList(1,2,4);
if(numbers.stream().anyMatch(x->x%2==1)) {
System.out.println("numbers集合中至少有1个奇数");
}
else {
System.out.println("numbers集合中没有奇数");
}
7.2 检查谓词是否匹配所有元素
allMatch检查流中的元素是否都能匹配给定的谓词
List<Integer> numbers=Arrays.asList(1,2,3);
if(numbers.stream().allMatch(x->x%2==1)) {
System.out.println("numbers集合中都是奇数");
}
else {
System.out.println("numbers集合中不全是奇数");
}
7.3 查找任意元素
findAny方法将返回当前流中的任意元素
List<Integer> numbers=Arrays.asList(1,2,3,4,5);
Optional<Integer> allEven=numbers.stream()
.filter(x->x%2==0)
.findAny();
System.out.println(allEven);
7.4 查找第一个元素
List<Integer> numbers=Arrays.asList(1,2,3,4,5);
Optional<Integer> firstEven=numbers.stream()
.filter(x->x%2==0)
.findFirst();
System.out.println(firstEven);//Optional[2]
8. 归约
8.1 元素求和
/*
* reduce的第一个参数:初始值 相当于给求和一个初值
* reduce的第二个参数:一个BinaryOperator<T>来将两个元素结合起来产生一个新值
*/
List<Integer> numbers=Arrays.asList(4,3,5,9);
int sum=numbers.stream().reduce(0, (a,b)->a+b);
System.out.println("sum="+sum);//21
8.2 最大值和最小值
/*
* reduce重载的变体
* 它不接受初始值,但是会返回一个Optional对象
*/
List<Integer> numbers=Arrays.asList(4,3,5,9);
Optional<Integer> maxNum=numbers.stream().reduce((x,y)->x>y?x:y);
Optional<Integer> minNum=numbers.stream().reduce((x,y)->x<y?x:y);
System.out.println("maxNum="+maxNum);//maxNum=Optional[9]
System.out.println("minNum="+minNum);//minNum=Optional[3]
9. 数值流
9.1 原始类型流特化
class Goods{
String name;
int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Goods(String name, int price) {
super();
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Goods [name=" + name + ", price=" + price + "]";
}
}
1. 映射到数值流
mapToInt返回一个IntStream(而不是一个Stream)
public static void main(String[] args) {
List<Goods> goods=Arrays.asList(
new Goods("Apple", 10),
new Goods("Banana", 5),
new Goods("Bread", 3),
new Goods("Milk", 15),
new Goods("Wine", 20));
//将Good对象流映射到价格流(整数流) 并求出价格总和
int priceSum=goods.stream().mapToInt(g->g.getPrice()).sum();
System.out.println(priceSum);//53
}
2.转换回对象流
boxed方法:要把原始流转换成一般流(这里每个int都会装箱成一个Integer)
List<Goods> goods=Arrays.asList(
new Goods("Apple", 10),
new Goods("Banana", 5),
new Goods("Bread", 3),
new Goods("Milk", 15),
new Goods("Wine", 20));
IntStream intStream=goods.stream().mapToInt(g->g.getPrice());
Stream<Integer> stream=intStream.boxed();
9.2 数值范围
Java 8引入了两个可以用于IntStream和LongStream的静态方法,帮助生成这种范围:range(左闭右开)和rangeClosed(左闭右闭)
//生成[1,50]内的所有偶数
IntStream evenNums=IntStream.rangeClosed(1, 50).filter(x->x%2==0);
evenNums.forEach(x->{System.out.print(" "+x);});
10. 构建流
10.1 由值创建流
使用静态方法Stream.of,通过显式值创建一个流
Stream<String> stream=Stream.of("Java","Python","Go");
stream.forEach(System.out::println);
10.2 由数组创建流
使用静态方法Arrays.stream从数组创建一个流
int[] numbers= {1,2,3,4,5,6};
IntStream stream=Arrays.stream(numbers);
stream.forEach(System.out::println);
10.3 由文件生成流
Stream<String> lines=null;
try {
lines=Files.lines(Paths.get("data.txt"),Charset.defaultCharset());
lines.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}finally {
lines.close();
}
10.4 由函数生成流:创建无限流
1. 迭代
/*
* iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator<t>类型)
* 这里,我们使用Lambda n-> n+2,返回的是前一个元素加上2
*/
Stream.iterate(0,n->n+2)
.limit(10)
.forEach(System.out::println);
/*
* 生成斐波那契数列
*/
Stream.iterate(new int[] {0,1},t->new int[] {t[1],t[0]+t[1]})
.limit(10)
.forEach(t->{System.out.println(t[0]+" "+t[1]);});
2. 生成
/*
* 生成10个随机数
*/
Stream.generate(Math::random)
.limit(10)
.forEach(System.out::println);
相关文章
暂无评论...