场景:现在有一个菜品集合,需要找出菜品中的卡路里小于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);
}
}
流是从支持数据处理操作的源生成的元素序列
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);
}
}
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是中间操作
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);
}
将流中的数据输出到终端上
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);
}
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]
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]
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]
/*
* 先找出集合中的偶数 再将这些偶数进行平方操作
*/
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]
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]
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集合中没有奇数");
}
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集合中不全是奇数");
}
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);
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]
/*
* reduce的第一个参数:初始值 相当于给求和一个初值
* reduce的第二个参数:一个BinaryOperator来将两个元素结合起来产生一个新值
*/
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
/*
* 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]
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();
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);});
使用静态方法Stream.of,通过显式值创建一个流
Stream<String> stream=Stream.of("Java","Python","Go");
stream.forEach(System.out::println);
使用静态方法Arrays.stream从数组创建一个流
int[] numbers= {1,2,3,4,5,6};
IntStream stream=Arrays.stream(numbers);
stream.forEach(System.out::println);
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();
}
1. 迭代
/*
* iterate方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator类型)
* 这里,我们使用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);