Java8新特性Lambda表达式&Stream流&方法引用最全集锦

本文详细介绍了Java8的Lambda表达式、Stream流和方法引用的使用,包括如何创建和操作流,如随机数流、范围操作、映射、过滤等。通过实例展示了在数据处理、文件读取、函数式编程中的应用,如计算斐波那契数列、处理Map、文件内容转单词流等。文章还探讨了Optional对象的创建和操作,以及如何在Stream中组合流和处理Optional结果。
摘要由CSDN通过智能技术生成

List bubbles = Arrays.asList(new Bubble(1), new Bubble(2), new Bubble(3));

System.out.println(bubbles.stream()

.mapToInt(b -> b.i)

.sum());

Set w = new HashSet<>(Arrays.asList(“It’s a wonderful day for pie!”.split(" ")));

w.stream()

.map(x -> x + " ")

.forEach(System.out::print);

System.out.println();

Map<String, Double> m = new HashMap<>();

m.put(“pi”, 3.14159);

m.put(“e”, 2.718);

m.put(“phi”, 1.618);

m.entrySet().stream()

.map(e -> e.getKey() + ": " + e.getValue())

.forEach(System.out::println);

}

}

输出结果:

6

a pie! It’s for wonderful day

phi: 1.618

e: 2.718

pi: 3.14159

  • 创建 List<Bubble> 对象后,只需简单调用所有集合中都有stream()

  • 中间操作 map() 会获取流中的所有元素,并且对流中元素应用操作从而产生新的元素,并将其传递到后续的流中。通常 map() 会获取对象并产生新的对象,但在这里产生了特殊的用于数值类型的流。例如,mapToInt() 方法将一个对象流(object stream)转换成为包含整型数字的 IntStream

  • 通过调用字符串的 split()来获取元素用于定义变量 w

  • 为了从 Map 集合中产生流数据,我们首先调用 entrySet() 产生一个对象流,每个对象都包含一个 key 键以及与其相关联的 value 值。然后分别调用 getKey()getValue() 获取值。

[](()随机数流

Random 类被一组生成流的方法增强了。代码示例:

// streams/RandomGenerators.java

import java.util.*;

import java.util.stream.*;

public class RandomGenerators {

public static void show(Stream stream) {

stream

.limit(4)

.forEach(System.out::println);

System.out.println("++++++++");

}

public static void main(String[] args) {

Random rand = new Random(47);

show(rand.ints().boxed());

show(rand.longs().boxed());

show(rand.doubles().boxed());

// 控制上限和下限:

show(rand.ints(10, 20).boxed());

show(rand.longs(50, 100).boxed());

show(rand.doubles(20, 30).boxed());

// 控制流大小:

show(rand.ints(2).boxed());

show(rand.longs(2).boxed());

show(rand.doubles(2).boxed());

// 控制流的大小和界限

show(rand.ints(3, 3, 9).boxed());

show(rand.longs(3, 12, 22).boxed());

show(rand.doubles(3, 11.5, 12.3).boxed());

}

}

输出结果:

-1172028779

1717241110

-2014573909

229403722

++++++++

2955289354441303771

3476817843704654257

-8917117694134521474

4941259272818818752

++++++++

0.2613610344283964

0.0508673570556899

0.8037155449603999

0.7620665811558285

++++++++

16

10

11

12

++++++++

65

99

54

58

++++++++

29.86777681078574

24.83968447804611

20.09247112332014

24.046793846338723

++++++++

1169976606

1947946283

++++++++

2970202997824602425

-2325326920272830366

++++++++

0.7024254510631527

0.6648552384607359

++++++++

6

7

7

++++++++

17

12

20

++++++++

12.27872414236691

11.732085449736195

12.196509449817267

++++++++

为了消除冗余代码,我创建了一个泛型方法 show(Stream<T> stream) (在讲解泛型之前就使用这个特性,确实有点作弊,但是回报是值得的)。类型参数 T 可以是任何类型,所以这个方法对 IntegerLongDouble 类型都生效。但是 Random 类只能生成基本类型 intlongdouble 的流。幸运的是, boxed() 流操作将会自动地把基本类型包装成为对应的装箱类型,从而使得 show() 能够接受流。

我们可以使用 Random 为任意对象集合创建 Supplier。如下是一个文本文件提供字符串对象的例子。

Cheese.dat 文件内容:

// streams/Cheese.dat

Not much of a cheese shop really, is it?

Finest in the district, sir.

And what leads you to that conclusion?

Well, it’s so clean.

It’s certainly uncontaminated by cheese.

我们通过 File 类将 Cheese.dat 文件的所有行读取到 List<String> 中。代码示例:

// streams/RandomWords.java

import java.util.*;

import java.util.stream.*;

import java.util.function.*;

import java.io.*;

import java.nio.file.*;

public class RandomWords implements Supplier {

List words = new ArrayList<>();

Random rand = new Random(47);

RandomWords(String fname) throws IOException {

List lines = Files.readAllLines(Paths.get(fname));

// 略过第一行

for (String line : lines.subList(1, lines.size())) {

for (String word : line.split("[ .?,]+"))

words.add(word.toLowerCase());

}

}

public String get() {

return words.get(rand.nextInt(words.size()));

}

@Override

public String toString() {

return words.stream()

.collect(Collectors.joining(" "));

}

public static void main(String[] args) throws Exception {

System.out.println(

Stream.generate(new RandomWords(“Cheese.dat”))

.limit(10)

.collect(Collectors.joining(" ")));

}

}

输出结果:

it shop sir the much cheese by conclusion district is

在这里你可以看到更为复杂的 split() 运用。在构造器中,每一行都被 split() 通过空格或者被方括号包裹的任意标点符号进行分割。在结束方括号后面的 + 代表 + 前面的东西可以出现一次或者多次。

我们注意到在构造函数中循环体使用命令式编程(外部迭代)。在以后的例子中,你甚至会看到我们如何消除这一点。这种旧的形式虽不是特别糟糕,但使用流会让人感觉更好。

toString() 和主方法中你看到了 collect() 收集操作,它根据参数来组合所有流中的元素。

当你使用 Collectors.joining(),你将会得到一个 String 类型的结果,每个元素都根据 joining() 的参数来进行分割。还有许多不同的 Collectors 用于产生不同的结果。

在主方法中,我们提前看到了 Stream.generate() 的用法,它可以把任意 Supplier<T> 用于生成 T 类型的流。

[](()int 类型的范围

IntStream 类提供了 range() 方法用于生成整型序列的流。编写循环时,这个方法会更加便利:

// streams/Ranges.java

import static java.util.stream.IntStream.*;

public class Ranges {

public static void main(String[] args) {

// 传统方法:

int result = 0;

for (int i = 10; i < 20; i++)

result += i;

System.out.println(result);

// for-in 循环:

result = 0;

for (int i : range(10, 20).toArray())

result += i;

System.out.println(result);

// 使用流:

System.out.println(range(10, 20).sum());

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值