java8 Lambda 与 Stream
2016-08-04 08:52
344 查看
Lambda
Lambda表达式的语法
基本语法:(parameters) -> expression
或
(parameters) ->{ statements; }
函数式接口
Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate<T>——接收
T对象并返回
boolean[译:断言-prɛdɪkət]
Consumer<T>——接收
T对象,不返回值[译:消费-kən’sumɚ]
Function<T, R>——接收
T对象,返回
R对象
Supplier<T>——提供
T对象(例如工厂),不接收值
UnaryOperator<T>——接收
T对象,返回
T对象
BinaryOperator<T>——接收两个
T对象,返回
T对象
除了上面的这些基本的函数式接口,我们还提供了一些针对
原始类型(Primitive type)的特化(Specialization)函数式接口,例如IntSupplier和LongBinaryOperator。(我们只为int、long和double提供了特化函数式接口,如果需要使用其它原始类型则需要进行类型转换)同样的我们也提供了一些针对多个参数的函数式接口,例如BiFunction
lambda 变量
lambda可以访问给它传递的参数,也能自己内部定义变量,当然还可以访问外部变量,不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)lambda眼中的this
在lambda中,this不是指向lambda表达式产生的那个对象,而是声明它的外部对象。lambda方法引用(Method reference)和构造器引用(construct reference)
方法引用:
方法引用可以在某些条件成立的情况下,更加简化lambda表达式的声明。方法引用语法格式有以下三种:objectName::instanceMethod ClassName::staticMethod ClassName::instanceMethod
前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。
最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。比如String::toLowerCase等同于x->x.toLowerCase()。
构造器引用
构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x->new BigDecimal(x)。java.util.stream.Stream 流
Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。流的构成
当我们使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换(Intermediate 操作)→执行操作(terminal 操作)获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。
Intermediate操作:
一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
Terminal操作:
一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
转换操作都是 lazy 的,多个转换操作只会在 Terminal 操作的时候融合起来,一次循环完成。
生成 Stream Source
从 Collection 和数组Collection.stream() Collection.parallelStream() Arrays.stream(T array) or Stream.of()
从 BufferedReader
java.io.BufferedReader.lines()
静态工厂
java.util.stream.IntStream.range() java.nio.file.Files.walk()
自己构建
java.util.Spliterator
其它
Random.ints() BitSet.stream() Pattern.splitAsStream(java.lang.CharSequence) JarFile.stream()
Reduce Stream
汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。注意:sum方法不是所有的Stream对象都有的,只有IntStream、LongStream和DoubleStream是实例才有。下面会分两部分来介绍汇聚操作:
可变汇聚:把输入的元素们累积到一个可变的容器中,比如Collection或者StringBuilder;
其他汇聚:除去可变汇聚剩下的,一般都不是通过反复修改某个可变对象,而是通过把前一次的汇聚结果当成下一次的入参,反复如此。比如reduce,count,allMatch
可变汇聚
可变汇聚对应的只有一个方法:collect,正如其名字显示的,它可以把Stream中的要有元素收集到一个结果容器中(比如Collection)。先看一下最通用的collect方法的定义(还有其他override方法):/** *Supplier supplier是一个工厂函数,用来生成一个新的容器; *BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中; *BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到) **/ <R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner);
List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10); List<Integer> numsWithoutNull = nums.stream().filter( 4000 num -> num != null). collect(() -> new ArrayList<Integer>(), (list, item) -> list.add(item), (list1, list2) -> list1.addAll(list2));
上面这段代码就是对一个元素是Integer类型的List,先过滤掉全部的null,然后把剩下的元素收集到一个新的List中。进一步看一下collect方法的三个参数,都是lambda形式的函数。
第一个函数生成一个新的ArrayList实例;
第二个函数接受两个参数,第一个是前面生成的ArrayList对象,二个是stream中包含的元素,函数体就是把stream中的元素加入ArrayList对象中。第二个函数被反复调用直到原stream的元素被消费完毕;
第三个函数也是接受两个参数,这两个都是ArrayList类型的,函数体就是把第二个ArrayList全部加入到第一个中;
但是上面的collect方法调用也有点太复杂了,没关系!我们来看一下collect方法另外一个override的版本
<R, A> R collect(Collector<? super T, A, R> collector);
这样清爽多了!少年,还有好消息,Java8还给我们提供了Collector的工具类–Collectors,其中已经定义了一些静态工厂方法,比如:Collectors.toCollection()收集到Collection中,Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。下面看看使用Collectors对于代码的简化:
List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null). collect(Collectors.toList());
其他汇聚
reduce方法:reduce方法非常的通用,后面介绍的count,sum等都可以使用其实现。Stream API
/***从集合中过滤掉Predicate返回为false 的元素。
*接收一个Predicate函数接口类型
* @return the new stream
*/
Stream<T> filter(Predicate<? super T> predicate);
/**
* 把流对象中的每一个元素转换成另一个对象元素。
* @return the new stream
*/
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//打印persons集合中的每一个人的FirstName。 persons.stream() .map(person -> person.getFirstName()) .forEach(e-> System.out.println(e));
/**
* 映射成Int 类型
* @return the new stream
*/
IntStream mapToInt(ToIntFunction<? super T> mapper);
/**
** 映射成Long 类型
* @return the new stream
*/
LongStream mapToLong(ToLongFunction<? super T> mapper);
/**
* 映射成Double类型
* @return the new stream
*/
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
/**
*把流对象中的每一个元素转换成新的流对象。
* @return the new stream
*/
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
//打印persons集合中的每一个人的FirstName 和 LastName。 //flatMap 把 每个人的FirstName 和 LastName 封闭成集合。 persons.stream() .flatMap(person -> Arrays.asList(person.getFirstName(),person.getLastName()) .stream()) .forEach(a-> System.out.println(a));
/**
* @see #flatMap(Function)
*/
IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
/**
* @see #flatMap(Function)
*/
LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
/**
* @see #flatMap(Function)
*/
DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
/**
* 过滤掉重复数据
* @return the new stream
*/
Stream<T> distinct();
/**
* 给实现Comparable接口的对象排序 从低到高。
* 若对象类型没有实现 comparable 接口 见: Stream sorted(Comparator
persons.stream() .sorted((p1,p2)->p1.getFirstName().length()-p2.getFirstName().length()) .forEach(e-> System.out.println(e.getFirstName()));
/**
* 对元素进行操作 但不转换元素类型。
* @return the new stream
*/
Stream<T> peek(Consumer<? super T> action);
persons.stream() .peek(person -> person.setAge(10)) .forEach(e-> System.out.println(e));
/**
* 返回 Stream 的前面 maxSize 个元素;
* @return the new stream
* @throws IllegalArgumentException if {@code maxSize} is negative
*/
Stream<T> limit(long maxSize);
/**
* 扔掉前 n 个元素
* @return the new stream
* @throws IllegalArgumentException if {@code n} is negative
*/
Stream<T> skip(long n);
/**
* 循环操作集合每一个元素
*/
void forEach(Consumer<? super T> action);
/**
* @see #forEach(Consumer)
*/
void forEachOrdered(Consumer<? super T> action);
/**
*把stream 转换为object类型数组
* @return an array containing the elements of this stream
*/
Object[] toArray();
/**
*把stream 转换为A类型数组
*/
<A> A[] toArray(IntFunction<A[]> generator);
Person[] ps = persons.stream() .limit(2) .toArray(Person[]::new); //或 Person[] ps1 = persons.stream() .limit(2) .toArray(index->new Person[index]); //或 Person[] ps2 = persons.stream() .limit(2) .toArray(new IntFunction<Person[]>() { @Override public Person[] apply(int value) { return new Person[value]; } }); Arrays.asList(ps).forEach(e-> System.out.println(e)); Arrays.asList(ps1).forEach(e-> System.out.println(e)); Arrays.asList(ps2).forEach(e-> System.out.println(e));
/**
* 把 Stream 元素组合起来。它提供一个起始值(种子),
* 然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。
* 从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
* 例如 Stream 的 sum 就相当于
* Integer sum = integers.reduce(0, (a, b) -> a+b); 或
* Integer sum = integers.reduce(0, Integer::sum);
* @return the result of the reduction
*/
T reduce(T identity, BinaryOperator<T> accumulator);
/**
* 依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。
* @return the result of the Optional
*/
Optional<T> reduce(BinaryOperator<T> accumulator);
Optional<String> sum = persons.stream().map(person -> person.getFirstName()).reduce((a,b)->a+","+b); System.out.println(sum.get());
/**
*
* @return the result of the reduction
* @see #reduce(BinaryOperator)
* @see #reduce(Object, BinaryOperator)
*/
<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner);
/**
*
* @return the result of the reduction
*/
<R> R collect(Supplier<R> supplier,BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner);
/**
*
* @return the result of the reduction
* @see #collect(Supplier, BiConsumer, BiConsumer)
* @see Collectors
*/
<R, A> R collect(Collector<? super T, A, R> collector);
/**
*
*/
Optional<T> min(Comparator<? super T> comparator);
/**
*
* @return an {@code Optional} describing the maximum element of this stream,
* or an empty {@code Optional} if the stream is empty
* @throws NullPointerException if the maximum element is null
*/
Optional<T> max(Comparator<? super T> comparator);
Optional<Integer> max = persons.stream().map(person -> person.getAge()).max((a,b)->a-b);
/**
*
* @return the count of elements in this stream
*/
long count();
/**
*Stream 中只要有一个元素符合传入的 predicate,返回 true
*/
boolean anyMatch(Predicate<? super T> predicate);
/**
* Stream 中全部元素符合传入的 predicate,返回 true ,stream 为empty 返回false
*/
boolean allMatch(Predicate<? super T> predicate);
/**
*Stream 中没有一个元素符合传入的 predicate,返回 true
*/
boolean noneMatch(Predicate<? super T> predicate);
/**
* 返回第一个元素
*/
Optional<T> findFirst();
/**
* 返回第一个元素
* @throws NullPointerException if the element selected is null
* @see #findFirst()
*/
Optional<T> findAny();
/**
* Returns a builder for a {@code Stream}.
*
* @param type of elements
* @return a stream builder
*/
public static<T> Builder<T> builder();
Stream.Builder<Person> builder = Stream.builder(); builder.add(new Person("Sindy", "Jonie", "uc", "female", 32, 2)); builder.add(new Person("Sindy1", "Jonie", "uc ", "female", 32, 2)); builder.add(new Person("Sindy1", "Jonie", "uc ", "female", 32, 2)); builder.build().forEach(person -> System.out.println(person.getFirstName()));
/**
* Returns an empty sequential {@code Stream}.
*
* @param the type of stream elements
* @return an empty sequential stream
*/
public static<T> Stream<T> empty();
/**
* Returns a sequential {@code Stream} containing a single element.
*
* @param t the single element
* @param the type of stream elements
* @return a singleton sequential stream
*/
public static<T> Stream<T> of(T t);
Stream<List<Person>> stream1 = Stream.of(persons); stream1.flatMap(ps -> ps.stream()).forEach(psi -> System.out.println(psi));
/**
* Returns a sequential ordered stream whose elements are the specified values.
*
* @param the type of stream elements
* @param values the elements of the new stream
* @return the new stream
*/
public static<T> Stream<T> of(T... values);
Stream<List<Person>> stream1 = Stream.of(persons, persons); stream1.flatMap(ps -> ps.stream()).forEach(psi -> System.out.println(psi));
/**
* iterate 跟 reduce 操作很像,接受一个种子值,和一个 UnaryOperator(例如 f)。
* 然后种子值成为 Stream 的第一个元素,f(seed) 为第二个,f(f(seed)) 第三个,以此类推。
* @return a new sequential {@code Stream}
*/
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f);
Stream.iterate(0, n -> n + 3).limit(10). forEach(x -> System.out.print(x + " "));. //输出结果:0 3 6 9 12 15 18 21 24 27
/**
*实现 Supplier 接口,控制流的生成。默认是串行(相对 parallel 而言)但无序的(相对 ordered 而言)。
*由于它是无限的,在管道中,必须利用 limit 之类的操作限制 Stream 大小。
* @param the type of stream elements
* @param s the {@code Supplier} of generated elements
* @return a new infinite sequential unordered {@code Stream}
*/
public static<T> Stream<T> generate(Supplier<T> s);
//样例1: Supplier<Integer> random = ()->new Random().nextInt();//等同 new Random()::nextInt; Stream.generate(random).limit(10).forEach(System.out::println); //样例2: IntStream.generate(() -> (int) (System.nanoTime() % 100)).limit(10).forEach(System.out::println); //样例3: Stream.generate(new PersonSupplier()). limit(10). forEach(p -> System.out.println(p.getName() + ", " + p.getAge())); private class PersonSupplier implements Supplier<Person> { private int index = 0; private Random random = new Random(); @Override public Person get() { return new Person(index++, "StormTestUser" + index, random.nextInt(100)); } }
/**
* 拼接两个流
*/
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b);
参考资料:
Java 8 中的 Streams API 详解:http://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/
深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法):
http://www.cnblogs.com/figure9/archive/2014/10/24/4048421.html
Java8初体验(二)Stream语法详解: http://ifeve.com/stream/
Java 8 特性 – 终极手册:http://ifeve.com/java-8-features-tutorial/
Java8初体验(一)lambda表达式语法:http://ifeve.com/lambda/
Java 8新特性探究(一)通往lambda之路_语法篇:http://my.oschina.net/benhaile/blog/175012
IntStream api
//生一个从 start 到 end 的集合, 步长为1public static IntStream range(int startInclusive, int endExclusive)
相关文章推荐
- [Java 8 Lambda] java.util.stream 简单介绍
- Java8 之 lambda表达式 与 Stream
- JAVA 8 StreamAPI 和 lambda表达式 总结(四)--stream的一些聚合操作
- 深入浅出理解JAVA 8 Lambda表达式 Stream
- Java8 Lambda表达式与Stream API (二): Stream API的使用
- [Java 8 Lambda] java.util.stream 简介
- JAVA8之lambda表达式详解,及stream中的lambda使用
- JAVA 8 StreamAPI 和 lambda表达式 总结(三)--Optional类型
- JAVA 8 StreamAPI 和 lambda表达式 总结(二)--Stream基本操作
- Stream Java8的集合类利器——走进Java Lambda
- JAVA8的新特性学习笔记-(lambda、stream)
- java8 新特性 实战详解 stream lambda 以及函数
- JAVA8之lambda表达式详解,及stream中的lambda使用
- java8初体验——optional、lambda、stream、map
- Java 8新特性:新语法方法引用和Lambda表达式及全新的Stream API
- Java8学习:Lambda表达式、Stream API和功能性接口 — 教程、资源、书籍和实例
- Java8特性详解 lambda表达式 Stream
- 在Java 8中对stream带有lambda表达式的操作进行调试
- java8 lambda表达式之 Stream常用方法
- Java 8 lambda stream forEach parallel 等循环与Java 7 for each 循环耗时测试