函数式编程 Lambda及Stream

参考书籍:Java8 函数式编程

AndroidStudio创建一个java Module
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
这里需要将java版本设置为1.8+

public class SimpleLambda {
    public static void main(String[] args){
        /**
         * 默认无参数 默认返回Runnable类型
         */
        Runnable runnable = () -> System.out.println("Hello Lambda");
        runnable.run();

        Runnable runnable1 = () -> {
            System.out.print("Hello");
            System.out.println(" Lambda");
        };
        runnable1.run();

        /**
         * 一个参数,无返回值, 默认返回Consumer类型
         */
        Consumer<Integer> tConsumer = (Integer x) -> System.out.println(x);
        Consumer<Double> doubleConsumer = (Double d) -> System.out.println(d);

        //由方法引用代替
        Consumer<Integer> tConsumer1 = System.out::println;
        Consumer<Double> doubleConsumer1 = System.out::println;

        tConsumer.accept(10);
        tConsumer1.accept(101);
        doubleConsumer.accept(20.0);
        doubleConsumer1.accept(201.0);

        Predicate<Integer> predicate = (x) -> x > 10;
        System.out.println(predicate.test(10));
        /**
         * 两个参数,有返回值
         */

        //lambda表达式默认返回类型IntBinaryOperator
        IntBinaryOperator intBinaryOperator = (x, y) -> x + y;
        System.out.println(intBinaryOperator.applyAsInt(3, 4));

        //lambda表达式默认返回类型DoubleBinaryOperator
        DoubleBinaryOperator doubleBinaryOperator = (double x, double y) -> x + y;
        System.out.println(doubleBinaryOperator.applyAsDouble(3.0, 4.0));

        BinaryOperator<Integer> add = (x, y) -> x + y;
        System.out.println(add.apply(10, 20));

    }
}
总结个简单的公式:

(参数...) -> 表达式;
(参数...) -> {代码块};
这里由于java8的类型推断,参数类型可写可不写,不写底层会根据方法的参数列表推断出来。
以上代码等号右边的lambda为什么返回等号左边的类型,看到下面的函数式接口就明白了

查看原码发现,Runnable多了一个注解 @FunctionalInterface(函数式接口)
package java.lang;

@FunctionalInterface
public interface Runnable {
    void run();
}

什么是函数式接口

简单说,只有一个抽象方法(不包括default static方法)的接口。
函数式接口其实就是Lambda表达式(又称为闭包)本身的类型

以下是java8中util.function包下的类,我总结了一个,分为5大种类
分别是Function, Operator, Consumer, Supplier, Predicate


Paste_Image.png

Stream

我们来看看java8新引进的Stream及对集合类的改进

Arrays:将Arrays转换为Stream

    String[] arrays = {"a1", "a2", "a3"};
    Stream<String> stream = Arrays.stream(arrays);

相关新加方法及重载方法:

    //
    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }
    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
    }

    //
    public static IntStream stream(int[] array) {
        return stream(array, 0, array.length);
    }

    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
    }

    //
    public static LongStream stream(long[] array) {
        return stream(array, 0, array.length);
    }

    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
    }

    //
    public static DoubleStream stream(double[] array) {
        return stream(array, 0, array.length);
    }

    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
    }

Collection:将各种继承Collection的接口(List, Set)转换为Stream

        List<String> stringList = new ArrayList<>();
        Stream<String> streamList = stringList.stream();

        Set<Long> map = new HashSet<>();
        Stream<Long> streamMap = map.stream();

Collection相关新加方法
java1.8后引入了接口的默认方法和静态方法,接口中也可以有实现方法了

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

除了以上可以获得Stream对象外,还有一些相应的方法:
先看一张结构图:

Paste_Image.png

尝试从以上子类中获得相应的Stream:

        IntStream intStream = IntStream.of(1, 2, 3);
        OptionalDouble average = intStream.average();
        System.out.println(average);//OptionalDouble[2.0]

        LongStream longStream = LongStream.of(1000, 2000, 3000);
        OptionalLong first = longStream.findFirst();
        System.out.println(first);//OptionalLong[1000]

        DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0);
        OptionalDouble max = doubleStream.max();
        System.out.println(max);//OptionalDouble[3.0]

        Stream<String> streamString = Stream.of("a", "b", "c", "d");
        long count = streamString.count();
        System.out.println(count);//4

得到Stream后,我们便可对其进行一系列操作,以上只是实现了几个简单的方法。接下来我们来看看一些常用的操作

常用的流操作

先来看两个概念:惰性求值方法,及早求值方法。
先记住,只要是方法返回的是Stream对象,则是惰性求值方法,其它的是及早求值方法。
这样的设计, 为链式调用提供便利。一般的调用顺序为:
1.获得流 (of)
2.惰性求值(of, filter, sorted)
3.及早求值(collect)

        List<String> list = Stream.of("Java", "Android", "Php", "IOS")//获得Stream对象
                .filter(s -> s.length() > 3)//过滤,只保留长度大于3的
                .sorted()//排序
                .collect(Collectors.toList());//将结果输出到List中
        System.out.println(list);//[Android, Java]
以此分类,先来看几个惰性求值方法:
map:将一种类型转换为另一种类型
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

        Function<String, String> stringStringFunction = s -> s.toUpperCase();
        List<String> list = Stream.of("Java", "Android", "Php", "IOS")
                .map(stringStringFunction)
                .collect(Collectors.toList());
        System.out.println(list.getClass().getSimpleName() + list);//ArrayList[JAVA, ANDROID, PHP, IOS]

        相当于:
        List<String> list = Stream.of("Java", "Android", "Php", "IOS")
                .map(s -> s.toUpperCase())
              //.map(String::toUpperCase)//或写成方法引用的格式,可以理解为以传入的参数为对象,调用该方法。
                .collect(Collectors.toList());
        System.out.println(list.getClass().getSimpleName() + list);//ArrayList[JAVA, ANDROID, PHP, IOS]

filter:过滤,保留符合参数条件的数据
Stream<T> filter(Predicate<? super T> predicate);
        List<String> list = Stream.of("Java", "Android", "Php", "IOS")
                .filter(s -> s.startsWith("A") | s.startsWith("I"))
                .collect(Collectors.toList());
        System.out.println(list.getClass().getSimpleName() + list);//ArrayList[Android, IOS]

flatMap:将多个Stream合并为一个Stream
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
        List<String> languageList = Arrays.asList("Java", "Android", "Php", "IOS");
        List<String> movieList = Arrays.asList("声之形", "你的名字", "千与千寻");
        List<String> list = Stream.of(languageList, movieList)
                .flatMap(Collection::stream)//这里的参数为List<String>
                .collect(Collectors.toList());
        System.out.println(list.getClass().getSimpleName() + list);//ArrayList[Java, Android, Php, IOS, 声之形, 你的名字, 千与千寻]
 
distinct:去重
Stream<T> distinct();
         List<Integer> collect = Stream.of(1, 2, 3, 4, 3, 5, 4)
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);//[1, 2, 3, 4, 5]
limit:限制个数
Stream<T> limit(long maxSize);
        List<Integer> collect = Stream.of(1, 2, 3, 4, 3, 5, 4)
                .limit(5)
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);//[1, 2, 3, 4]
peek:用于调试
Stream<T> peek(Consumer<? super T> action);
        Stream.of("one", "two", "three", "four")
                       .filter(e -> e.length() > 3)
                       .peek(e -> System.out.println("Filtered value: " + e))
                       .map(String::toUpperCase)
                       .peek(e -> System.out.println("Mapped value: " + e))
                       .collect(Collectors.toList());
        输出:
        Filtered value: three
        Mapped value: THREE
        Filtered value: four
        Mapped value: FOUR
skip:跳过若干个数据
Stream<T> skip(long n);
        List<Integer> collect = Stream.of(1, 2, 3, 4, 5, 6)
                .skip(2)
                .collect(Collectors.toList());
        System.out.println(collect);//[3, 4, 5, 6]
再来看几个及早求值方法:
collect:从流中生成相应的集合
<R, A> R collect(Collector<? super T, A, R> collector);
        List<String> list = Stream.of("Java", "Android", "Php", "IOS")
                .filter(s -> s.length() > 3)
                .sorted()
                .collect(Collectors.toList());
        System.out.println(list.getClass().getSimpleName() + list);//ArrayList[Android, Java]

        Set<String> set = Stream.of("Java", "Android", "Php", "IOS")
                .filter(s -> s.length() > 3)
                .sorted()
                .collect(Collectors.toSet());
        System.out.println(set.getClass().getSimpleName() + set);//HashSet[Java, Android]

        Function<String, String> keyMapper = s -> s + "key";
        Function<String, String> valueMapper = s -> s + "value";
        Map<String, String> map = Stream.of("Java", "Android", "Php", "IOS")
                .filter(s -> s.length() > 3)
                .sorted()
                .collect(Collectors.toMap(keyMapper, valueMapper));
        System.out.println(map.getClass().getSimpleName() + map);//HashMap{Javakey=Javavalue, Androidkey=Androidvalue}

max/min: 按照一定规则,获得最大,最小值
Optional<T> max(Comparator<? super T> comparator);
        Optional<String> max = Stream.of("Java", "Android", "Php", "IOS")
                .max(Comparator.comparing(String::length));
        System.out.println(max.get());//Android
count: 获得数据的个数
long count();
        long count = Stream.of("Java", "Android", "Php", "IOS").count();
        System.out.println(count);//4
reduce: 从一组值中生成一个值 (以上的max, min, count都是reduce操作)
T reduce(T identity, BinaryOperator<T> accumulator);
        Integer reduce = Stream.of(1, 2, 3, 4, 5).reduce(0, (first, second) -> first + second);
        System.out.println(reduce);//15

forEach:遍历输出
void forEach(Consumer<? super T> action);
        Stream.of(1, 2, 3, 4, 5).forEach(System.out::println);

未完待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容