Java中lambda表达式去重_JAVA8中Lambda和Stream

Java8于2014年3月份发布,其主要更新的特性有:函数式接口、Lambda 表达式、集合的流式操作、注解的更新、安全性的增强、IO\NIO 的改进、完善的全球化功能等,本文将介绍Lambda表达式与集合流试操作。

函数式接口

Java8引入的一个重要的思想就是函数式编程。 提到函数式,必须提到函数式接口。在Java8中对函数式接口的注解是@FunctionalInterface,任何一个只有一个抽象方法的接口都默认为是函数式接口,@FunctionalInterface注解是非必须的。如果在一个接口上加上该注解,那么这个接口就只能有一个抽象方法。如下

@FunctionalInterface

public interface TestInterface { void test(); }

也可以省略注解

public interface TestInterface { void test(); }

几种常见的函数式接口比如说Function 支持传入一个参数T并且返回R;

Predicate 传入一个参数T返回一个boolean类型等等。

接口

参数

返回类型

Function

T

R

Predicate

T

boolean

Supplier

None

T

UnaryOperator

T

T

Consumer

T

void

BinaryOperator

(T, T)

T

Lambda

我们可以用Lambda表达式来实例化函数式接口,避免了内部类冗余的代码。

Lambda表达式的组成

Lambda表达式有多种形式,总结来说不外乎三部分组成:第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数,参数中可以指定类型,也可以省略类型(如果是单个参数的情况下括号可以省略,无参或者多个参数则不能省略括号);第二部分为一个箭头符号:-> 是lambda的运算符;第三部分为方法体,可以是表达式和代码块。如下

TestInterface t = () -> System.out.println("lambda");

如果有入参,第三部分是代码块,而且实现的接口有返回值的时候需要加上{}且要把结果return

public interface LongToInt { int toInt(Long i); }

LongToInt lti = i -> {

if(i != null){

return i.intValue();

} else return 0;

};

在Java8以前要想实例化接口使用匿名内部类来处理,代码显得啰嗦而不易读

new TestInterface(){

public void test() {

System.out.println("lambda");

}

}.test();

使用lambda表达式后就可以简化成一行代码

((TestInterface)() -> System.out.println("lambda")).test();

Lamdba中的方法引用

如果方法体只是简单的函数引用则可以直接使用 :: 引用,更大程度上简化我们的代码。Java8中的 :: 符号表示:符号左边的对象(List res),调用符号右边的方法(add()),参数即为lamdba表达式的参数(Integer)。

List res = Lists.newArrayList();

ints.forEach(res :: add);

Stream

java8中引用stream可以对集合进行过滤、排序、映射等操作。

生成Stream

Java8的stream分为两种,即并行和串行。可以通过Collection.parallelStream()生成一个并行流,可以通过Collection.stream()生成一个串行流(默认的stream开启的是串行流)。Stream通过StreamSupport.stream(Spliterator spliterator, boolean parallel)方法中的parallel来判断是否生成并行流。

default Stream stream() {return StreamSupport.stream(spliterator(), false);}

default Stream parallelStream() {return StreamSupport.stream(spliterator(), true);}

我们还可以将生成的stream通过stream.parallel()或stream.sequential()转换成并行或者串行。

通过方法名我们不难理解,串行流在一个线程依次执行,而并行流则是在多个线程同时执行。并行流的执行效率远远大于串行流。

Stream应用

一般在Java中使用stream有三步:第一步生成stream;第二步对stream进行转换;第三步聚合操作得到想要的结果。

Stream的中间转换操作

distinct: 对stream中的元素进行去重操作。

filter: 对stream中包含的元素使用给定的过滤函数进行过滤操作,而filter方法传的参数就是Predicate实例化,即可以. 使用上面提到的lambda表达式(新的stream中只包含Predicate中判定为true的元素)。

map: 对stream中包含的元素使用给定的转换函数进行转换操作.这个方法有三个引申方法,分别是:mapToInt,mapToLong和mapToDouble,在map中执行转换函数,再转换新的的stream元素为Integer, Long, Double类型。转换函数类型为Function,用lambda表达式比较方便。

flatMap:会把要求Function的返回值是stream即在map里面用stream的子元素再生成一个stream,把所有的子元素生成的stream压缩成一个stream。

boxed: 将LongStream、IntStream、DoubleStream转换成对应类型的Stream。

limit: 对一个stream进行截断操作,获取其前n个元素,如果原stream中包含的元素个数小于n,那就获取其所有的元素;

skip: 返回一个丢弃原stream的前n个元素后剩下元素组成的新stream,如果原stream中包含的元素个数小于n,那么返回空stream;

Stream的聚合操作

collect: 将stream元素收集起来,可以通过Collectors.toList()实现将stream转换为List的操作。

count: 得到stream的元素个数。

findFirst: 得到第一个元素。

max: 需要自定义一个Comparator来比较元素的大小,返回最大值。

min: 需要自定义一个Comparator来比较元素的大小,返回最小值。

allMatch: 判断元素是否全部符合Predicate标准。

anyMatch: 判断元素是否有一个或者多个符合Predicate标准。

noneMatch: 判断元素是否都不符合Predicate标准。

List strList = Lists.newArrayList("11 ", "213 ", " 11", "23", "145", "15 ", "2 ", " 3", "");

List ints = Lists.partition(strList, 3).stream().flatMapToInt(strs -> strs.stream().filter(str -> str != null && !Objects.equals(str, "")).mapToInt(str -> Integer.valueOf(str.trim()))).distinct().limit(5).skip(3).boxed().collect(Collectors.toList());

上面的例子是把一个List,先通过Guava Lists将该list按每组3个拆分生成List>再转换为Stream>,再flatMapToInt,在map里面再将list转换为Stream,过滤掉空字符串和null,再mapToInt去重,取前5个,再丢弃前三个元素,再转换成一个List。

注:所有的聚合操作、foreach操作都会把stream关闭,如果一个stream被关闭后,不能再次对stream进行任何操作。

你可能感兴趣的:(Java中lambda表达式去重_JAVA8中Lambda和Stream)