类准备:
List<Dish> menu = Arrays.asList(
new Dish("pork", false, 800, Type.MEAT),
new Dish("beef", false, 700, Type.MEAT),
new Dish("chicken", false, 400, Type.MEAT),
new Dish("french fries", true, 530, Type.OTHER),
new Dish("rice", true, 350, Type.OTHER),
new Dish("season fruit", true, 120, Type.OTHER),
new Dish("pizza", true, 550, Type.OTHER),
new Dish("prawns", false, 300, Type.FISH),
new Dish("prawns", false, 300, Type.FISH),
new Dish("prawns", false, 300, Type.FISH),
new Dish("salmon", false, 450, Type.FISH) );
List<Integer> numbers = Arrays.asList(1,1,4,10,343,22,345,21);
public class Dish {
private final String name;
private final boolean vegetarian;
private final int calories;
private final Type type;
public Dish(String name, boolean vegetarian, int calories, Type type) {
this.name = name;
this.vegetarian = vegetarian;
this.calories = calories;
this.type = type;
}
public String getName() {
return name;
}
public boolean isVegetarian() {
return vegetarian;
}
public int getCalories() {
return calories;
}
public Type getType() {
return type;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Dish dish = (Dish) o;
return vegetarian == dish.vegetarian &&
calories == dish.calories &&
Objects.equals(name, dish.name) &&
type == dish.type;
}
@Override
public int hashCode() {
return Objects.hash(name, vegetarian, calories, type);
}
public enum Type {
MEAT,FISH,OTHER
}
筛选和切片
filter方法:
该操作会接受一个返回boolean的函数作为参数,并返回一个包括所有符合条件的元素的流
List<Dish> vegetarianMenu = menu.stream().filter(Dish::isVegetarian).collect(Collectors.toList());
distinct方法:
它会返回一个元素各异【不含相同值】(根据流所生成元素的hashCode和equals方法实现)的流 —》 【去重】
对于对象一定要重写hashCode和equals方法
List<Dish> vegetarianMenuDis = menu.stream().distinct().collect(Collectors.toList());
limit方法:
该方法会返回一个不超过给定长度的流
limit作用在有序集合上同时也可作用在无序集合上,都是返回前n个元素
List<Dish> vegetarianMenuLimit = menu.stream().limit(3).collect(Collectors.toList());
skip方法:
返回一个扔掉了前n个元素的流,如果流中元素不足n个,则返回一个空流。
List<Dish> vegetarianMenuSkip = menu.stream().skip(3).collect(Collectors.toList());
映射
map方法:
接受一个函数作为参数这个函数会被应用到每个元素上,并将其映射成一个新的元素
List<String> dishName = menu.stream().map(Dish::getName).collect(Collectors.toList());
List<Integer> dishlength= menu.stream().map(Dish::getName).map(String::length).collect(Collectors.toList());
Arrays.stream():
接受一个数组并产生一个流
String[] arrayOfWords = {"Goodbye", "World"};
Stream<String> streamOfwords = Arrays.stream(arrayOfWords);
flatMap方法:
将各个数组映射成流的内容,并不是分别映射成一个流
flatmap方法把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流。
将list中的单词切割,去除重复字母
List<String> words = Arrays.asList("hello","world");
List<String> wordsF = words.stream().map((String w) -> w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
组合成一个二维数组
List<Integer> numbers1 = Arrays.asList(1, 2, 3);
List<Integer> numbers2 = Arrays.asList(3, 4);
List<int[]> pairs = numbers1.stream()
.flatMap((Integer i) -> numbers2.stream().map((Integer j) -> new int[]{i, j}))
.collect(Collectors.toList());
查找和匹配
anyMatch方法:
检查输入的条件是否至少匹配一个元素,是一个终端操作
anyMatch方法返回一个boolean
boolean isAny = menu.stream().anyMatch(Dish::isVegetarian);
allMatch方法:
检查输入的条件是否匹配所有元素
boolean isAll = menu.stream().allMatch(d -> d.getCalories() > 300);
noneMatch方法:
allMatch的反义词,没有任何元素与给定的条件匹配
boolean isNone = menu.stream().noneMatch(d -> d.getType().equals("XXX"));
findAny方法:
返回当前流中的任意元素
Optional<Dish> dish = menu.stream().findAny();
Optional<T>类(java.util.Optional)是一个容器类,代表一个值存在或不存在。
findFirst方法
查找第一个元素
Optional<Dish> firstDish = menu.stream().findFirst();
何时使用findFirst和findAny:
找到第一个元素在并行上有更多的限制,如果不关心返回的元素是哪个,则使用findAny,它在使用并行流时限制较少
归约
reduce方法
将流中所有元素反复结合起来,得到一个值
educe接受两个参数:
一个初始值,这里是0;
一个BinaryOperator<T>来将两个元素结合起来产生一个新值
求和运算
1.使用map转换成int
2.使用reduce将所有元素相加
int sum = menu.stream().map(Dish::getCalories).reduce(0,(a,b) -> a+b);
int sum = menu.stream().map(Dish::getCalories).reduce(0,(a,b) -> a*b);
int sum = menu.stream().map(Dish::getCalories).reduce(0,(a,b) -> a-b);
int sum = menu.stream().map(Dish::getCalories).reduce(0,(a,b) -> a/b);
int sum = numbers.stream().reduce(0, Integer::sum);
最大值
List<Integer> numbers = Arrays.asList(1,1,4,10,343,22,345,21);
Optional<Integer> max = numbers.stream().reduce(Integer::max);
最小值
Optional<Integer> min = numbers.stream().reduce(Integer::min);
count方法:
返回集合中对象的总个数
long count = numbers.stream().count();
原始类型流特化,专门支持处理数值流
IntStream、 DoubleStream和LongStream,分别将流中的元素特化为int、 long和double
解决问题:避免了暗含的装箱成本
映射到数值流
将流转换为特化版本的常用方法是mapToInt、 mapToDouble和mapToLong
int sumMp = menu.stream().mapToInt(Dish::getCalories).sum();
mapToInt返回一个IntStream流。
如果流是空的, sum默认返回0。
IntStream还支持其他的方便方法,如max、 min、 average等。
转换回对象流
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream<Integer> stream1 = intStream.boxed();
默认值OptionalInt
对于三种原始流特化,也分别有一个Optional原始类型特化版本: OptionalInt、 OptionalDouble和OptionalLong
为了区分到底是最大值0还是没有值返回的0
OptionalInt maxCalories = menu.stream().mapToInt(Dish::getCalories).max();
如果没有最大值的话,显式提供一个默认最大值
int max = maxCalories.orElse(1);
数值范围
IntStream和LongStream ---->>> range【起始值,不包含结束值】和rangeClosed【结束值,包含结束值】
求1-100以内的偶数
IntStream evenNumbers = IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0);
遍历1:
evenNumbers.forEach(i -> System.out.println(i));
遍历2:
int[] arraysp = evenNumbers.toArray();
for (int i = 0; i < arraysp.length; i++) {
System.out.println(arraysp[i]);
}
由值创建流
静态方法Stream.of,通过显式值创建一个流。可以接受任意数量的参数
字符流,转换成大写输出
Stream<String> stringStream = Stream.of("a","b","c");
stringStream.map(String::toUpperCase).forEach(System.out::println);
空流
Stream<String> emptyStream = Stream.empty();
由数组创建流
静态方法Arrays.stream,创建一个数组流,接受一个数组作为参数
int[] ints = {2, 3, 5, 7, 11, 13};
int suml = Arrays.stream(ints).sum();
由文件生成流
data.txt
google-mysql-mysql-Python-google-mysql-java
java-mysql
Python-Python-mysql
mysql-google-google-java
查看一个文件中有多少不相同的单词
long uniqueWords = 0;`在这里插入代码片`
try (Stream<String> lines = Files.lines(Paths.get("d://data.txt"),Charset.defaultCharset())){
uniqueWords = lines.flatMap(line -> Arrays.stream(line.split("-"))).distinct().count();
}catch (IOException e){
e.printStackTrace();
}
Files.lines:返回一个由指定文件中的各行构成的字符串流
由函数生成流:创建无限流
Stream API提供了两个静态方法来从函数生成流: Stream.iterate和Stream.generate。
这两个操作可以创建无限流:和固定集合创建的流不一样,没有固定的大小,按需创建值;为了避免无穷打印无穷个的值,需要加以limit(n)进行限制
迭代:Stream.iterate
有序,结果取决于前一次应用
此操作生成一个无限流——这个流没有结尾,因为值是按需计算的,可以永远计算下去。
使用limit限制无限循环
获取10个偶数
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]+"]"));
斐波纳契数列
Stream.iterate(new int[]{0,1},t -> new int[]{t[1],t[0]+t[1]})
.limit(10)
.map(t -> t[0])
.forEach(System.out::println);
生成:Stream.generate
generate不是依次对每个新生成的值应用函数的。它接受一个Supplier类型的Lambda提供新的值
生成5个double类型的随机数
Stream.generate(Math::random).limit(5).forEach(System.out::println);