Java8函数式编程1-简介和流

来源:互联网 发布:付融宝怎么样 知乎 编辑:程序博客网 时间:2024/05/06 10:57

参考并建议阅读:《Java 8函数式编程》
转载请注明出处:http://blog.csdn.net/cuiods/article/details/53676090


一、什么是函数式编程

函数式编程的核心是:在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值。
为支持函数式编程,Java8 引入了Lambda表达式。我对Java8中的Lambda表达式的理解是,使用匿名函数替换Java中的样本代码(匿名内部类)。

Runnable noArguments = () -> System.out.println("Hello World");BinaryOperator<Long> add = (x, y) -> x + y;BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

Lambda表达式的类型依赖于上下文环境,是由编译器推断出来的。在引用外部变量时,不管是否声明为final(Java8取消了必须声明为final的限制),这个变量还是要是终态的,否则编译器会报错(local variables referenced from a Lambda expression must be final or effectively final)。也就是说,Lambda表达式在引用外部变量时引用的是值,而不是变量。

二、流(Stream)

1、内部迭代与外部迭代

在操作集合类时,我们通常需要编写大量代码。比如在计算来自伦敦的艺术家人数时,我们通常的写法是

int count = 0;for (Artist artist : allArtists) {    if (artist.isFrom("London")) {        count++;    }}

这样的迭代叫做外部迭代,外部迭代的实际原理是获取集合的迭代器Iterator,使用Iterator来控制迭代过程。而内部迭代的含义是迭代在集合内部控制下进行。Stream(流)是用函数式编程方法在集合类上进行复杂操作的工具,使用Stream可以将上面的迭代改写为:

long count = allArtists.stream()                       .filter(artist -> artist.isFrom("London"))                       .count();

在这种方法中,filter只是刻画描述了stream,并没有产生新的集合,它的返回值还是stream,这称为惰性求值方法,而count这样从stream产生值的方法叫做及早求值方法,这样的方法返回值一般为空或另一个值。

2、常用的流操作

(1)collect(toList())

collect(toList())方法由Stream里的值生成一个列表,是一个及早求职方法。

List<String> collected = Stream.of("a","b","c")                               .collect(Collectors.toList());

(2)map

如果有一个函数可以将一种类型的值转换成另一种类型,map操作就可以使用该函数,将一个流中的值转换成一个新的流。

List<String> collected = Stream.of("a", "b", "hello")                               .map(string -> string.toUpperCase())                                .collect(toList());assertEquals(asList("A", "B", "HELLO"), collected);

传给map的lambda表达式必须是实现Function接口的一个实例。

(3)filter

关于filter上面已经给过示例,很多情况下我们需要在列表中选出符合条件的某几项,这一类代码称为filter模式,其核心思想是保留stream中的一些元素而过滤掉其他的元素。
传给filter的lambda表达式必须是实现Predicate接口的一个实例。

(4)max和min

List<Track> tracks = asList(new Track("Bakai", 524),                            new Track("Violets for Your Furs", 378),                            new Track("Time Was", 451));Track shortestTrack = tracks.stream()                            .min(Comparator.comparing(track->track.getLength()))                            .get();

min或max的输入参数是一个Comparator对象,Java8提供了新的方法comparing,我们需要提供需要比较内容的存取方法就可以实现比较器。

(5)reduce

reduce操作可以从一组值中生成一个值。上面示例的count、min、max其实都是reduce操作。

int count = Stream.of(1,2,3)                  .reduce(0, (acc,element) -> acc + element);

第一个参数0为初始值,第二个参数lambda表达式是一个BinaryOperator实例。

3、多次调用流操作

尽量使用流的链式调用,而不是每一步强制对函数求值。
错误使用流的例子:

List<Artist> musicians = album.getMusicians()                              .collect(toList());List<Artist> bands = musicians.stream()                              .filter(artist -> artist.getName().startsWith("The"))                              .collect(toList());Set<String> origins = bands.stream()                           .map(artist -> artist.getNationality())                           .collect(toSet());

正确的写法应该是:

Set<String> origins = album.getMusicians()                      .filter(artist -> artist.getName().startsWith("The"))                      .map(artist -> artist.getNationality())                      .collect(toSet());

使用链式调用可以提高可读性和效率,便于自动并行化处理。


参考并建议阅读:《Java 8函数式编程》

1 0
原创粉丝点击