java8新特性(四):Stream流的使用


过滤出素食
List vegetarian = menu.stream().filter(Dish::isVegetarian).collect(Collectors.toList());
java8新特性(四):Stream流的使用_第1张图片



过滤出偶数,并且不重复的元素。
List numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream()
.filter(i -> i % 2 == 0)
.distinct()
.forEach(System.out::println);

java8新特性(四):Stream流的使用_第2张图片

截断流
List dishes = menu.stream()
.filter(d -> d.getCalories() > 300)
.limit(3)
.collect(toList());


跳过元素
List dishes = menu.stream()
.filter(d -> d.getCalories() > 300)
.skip(2)
.collect(toList());


映射

List dishNames = menu.stream()
.map(Dish::getName)
.collect(toList());



List words = Arrays.asList("Java8", "Lambdas", "In", "Action");
List wordLengths = words.stream()
                                                                 .map(String::length)
                                                                 .collect(toList());


展开流

List uniqueCharacters = words.stream().map(w -> w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
java8新特性(四):Stream流的使用_第3张图片



查找和匹配

任意匹配
if(menu.stream().anyMatch(Dish::isVegetarian)){
          System.out.println("The menu is (somewhat) vegetarian friendly!!");
}

全部匹配
boolean isHealthy = menu.stream().allMatch(d -> d.getCalories() < 1000);


全部不匹配
boolean isHealthy = menu.stream().noneMatch(d -> d.getCalories() >= 1000);


获取任意一个元素
Optional dish =menu.stream() .filter(Dish::isVegetarian) .findAny();


归约
将一个流中的元素反复结合运算得到一个值。

使用循环求和
List numbers = new ArrayList<>();
int sum1 = 0;
for(int x: numbers){
    sum1 += x;
}

使用流的API求和
int sum2 = numbers.stream().reduce(0, (a,b) -> a + b);
java8新特性(四):Stream流的使用_第4张图片

求最大值
Optional max = numbers.stream().reduce(Integer::max);

求最小值
Optional min = numbers.stream().reduce(Integer::min);

使用reduce相对于使用逐步迭代的好处在于,外部迭代改成了内部迭代,在需要实现并行执行的操时作变得简单。

有状态操作和无状态操作
比如map或者filter会从输入流中获取每一个元素,并且在输出流中得到一个结果,这些操作没有内部状态,称为无状态操作
但是像reduce、sum、max这些操作都需要内部状态来累计计算结果,所以称为有状态操作
还有一些操作sort、distinct,看上去和filter、map差不多,他们接收一个流,再生成一个流,但是区别在于排序和去重复项需要知道先前的历史。比如排序就需要将所有元素放入缓存区后才能给输出流加入一个项目,这个操作对缓存的要求是无上限的,流有多大就需要多大的缓存才能进行运算。这些操作也是有状态操作

中间操作和终端操作
 操作 类型 返回值 使用的函数接口或者类型
filter
中间操作
Stream
Predicate
distinct
中间操作,有状态,无边界 Stream
skip
中间操作,有状态,有边界 Stream
long
limit
中间操作,有状态,有边界 Stream
long
map
中间操作
Stream
Function

flatMap
中间操作
Stream
Function>
sorted
中间操作,有状态,无边界
Stream
Comparator
anyMatch
终端操作
boolean
Predicate
noneMatch
终端操作
boolean
Predicate
allMatch
终端操作
boolean
Predicate
findAny
终端操作
Optional


findFirst
终端操作 Optional
forEach
终端操作
void
Consumer
collect
终端操作 R
Collector
reduce
终端操作,有状态,有边界
Optional
BinaryOperator
count
终端操作
long

中间操作就像是水管的一部分,终端操作就像水龙头,增加水管长度不会消耗水,只有打开水龙头才会开始消耗水。

Java5的时候就引入了自动装箱拆箱的功能, 在对包装类型进行数学计算的时候,包装类型就会被自动拆箱成基本类型, 而将一个基本类型的值赋值给一个包装类型的变量或者放入集合中时基本类型又会被自动装箱成包装类型,这个过程是需要消耗计算性能的。Java8的包装类型的流的计算过程中同样包含了对基本类型的自动装箱和拆箱的过程,所以Java8又引入了三个原始类型的流用来解决这个问题。(IntStream, DoubleStream和LongStream), 分别对应基本类型int, double, long,从而避免了自动装箱和拆箱的性能消耗。
基本类型的使用:
Stream的求和: int sum3 = menu.stream().map(Dish::getColories).reduce(0, Integer::sum);
使用IntStream的求和: int sum4 = menu.stream().mapToInt(Dish::getColories).sum();

创建一个流

1, 使用range方法给定一个范围来创建一个基本类型的流。
IntStream intStream = IntStream.range(1,100);

2,直接给值来创建流
Stream stream = Stream.of("walker","sun","is","the","best");

3,由数组创建流
IntStream stream2 = Arrays.stream(numbers2);


4, 由文件生成流
try {
    Stream lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
catch (IOException e) {
    e.printStackTrace();
}

5,由函数生成流
迭代: Stream.iterate(0, n -> n + 2).limit(10) .forEach(System.out::println);

生成:Stream.generate(Math::random).limit(5) .forEach(System.out::println);


你可能感兴趣的:(Java8)