函数式编程 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);

未完待续。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容