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

参考并建议阅读:《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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 8 引入了函数式编程的概念,其中最重要的两个特性是 Lambda 表达式和 Stream API。下面将对这两个特性进行详细介绍。 1. Lambda 表达式 Lambda 表达式是一种匿名函数,它可以作为参数传递给方法或存储在变量中。Lambda 表达式的语法如下: ``` (parameter1, parameter2, ..., parameterN) -> { statement1; statement2; ... } ``` 其中,参数列表可以为空,也可以包含多个参数;箭头符号 "->" 用于将参数列表和 Lambda 表达式的主体分开;体可以是一个语句块,也可以是一个表达式。 下面是一个 Lambda 表达式的例子: ```java (int x, int y) -> { return x + y; } ``` 这个 Lambda 表达式接受两个整数参数 x 和 y,返回它们的和。 Lambda 表达式可以用于函数式接口,即只包含一个抽象方法的接口。例如,下面是一个函数式接口的定义: ```java interface MyInterface { int myMethod(int x, int y); } ``` 可以使用 Lambda 表达式来实现这个接口: ```java MyInterface obj = (int x, int y) -> { return x + y; }; ``` Lambda 表达式还可以使用方法引用来简化代码。例如,可以使用静态方法引用来实现上面的例子: ```java MyInterface obj = Integer::sum; ``` 2. Stream API Stream API 是一种用于处理集合的 API,它提供了一种式处理集合的方式。Stream API 可以用于对集合进行过滤、映射、排序等操作。 下面是一个使用 Stream API 进行过滤和映射的例子: ```java List<String> list = Arrays.asList("apple", "banana", "orange", "pear"); List<String> result = list.stream() .filter(s -> s.startsWith("a")) .map(String::toUpperCase) .collect(Collectors.toList()); ``` 这个例子首先创建了一个包含四个字符串的列表,然后使用 stream() 方法将其转换为一个。接着使用 filter() 方法过滤出以字母 "a" 开头的字符串,再使用 map() 方法将这些字符串转换为大写形式。最后使用 collect() 方法将结果收集到一个列表中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值