山寨Stream API

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

一个需求

List<Person> list = new ArrayList<>();

list.add(new Person("李健", 46));

list.add(new Person("周深", 28));

list.add(new Person("张学友", 59));

请筛选出年龄大于40的歌手的名字

请大家先自行实现这个需求。

我的实现方式

我写了一个山寨版的Stream API,实现了其中的filter()和map(),底层原理稍有不同,仅做知识引入。

乍一看很麻烦,好像还不如直接写各种for,但我是为了复用,所以抽取了MyList类。

要想实现上面的编码形式,需要两块砖:

  • 链式编程
  • 把Lambda表达式作为接口实例传递(必须是函数式接口)

关于Lambda表达式,请参考《Lambda表达式》。

链式编程简单来说就是一个方法返回引用本身:

public class ChainCall {
    public static void main(String[] args) {
        Person bravo1988 = new Person().setName("mx").setAge(18).setMoney(1000.0);
    }
}

class Person{
    private String name;
    private Integer age;
    private Double money;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public Double getMoney() {
        return money;

    }
    
    public Person setName(String name) {
        this.name = name;
        // set方法要返回this,方便继续调用下一个set
        return this;
    }
    
    public Person setAge(Integer age) {
        this.age = age;
        return this;
    }

    public Person setMoney(Double money) {
        this.money = money;
        return this;
    }
}

OK,交代完毕,接下来请大家把我的代码拷贝到本地运行看看:

/**
 * @author mx
 */
public class MockStream {

    public static void main(String[] args) throws JsonProcessingException {

        MyList<Person> personMyList = new MyList<>();
        personMyList.add(new Person("李健", 46));
        personMyList.add(new Person("周深", 28));
        personMyList.add(new Person("张学友", 59));

        // 需求:过滤出年龄大于40的歌手的名字
        MyList<String> result = personMyList.filter(person -> person.getAge() > 40).map(Person::getName);
        prettyPrint(result.getList());

        System.out.println("\n---------------------------------------------\n");

        // 对比真正的Stream API
        List<Person> list = new ArrayList<>();
        list.add(new Person("李健", 46));
        list.add(new Person("周深", 28));
        list.add(new Person("张学友", 59));

        List<String> collect = list
                .stream()                               // 真正的Stream API需要先转成stream流
                .filter(person -> person.getAge() > 40) // 过滤出年纪大于40的歌手
                .map(Person::getName)                   // 拿到他们的名字
                .collect(Collectors.toList());          // 整理成List<String>

        prettyPrint(collect);
    }


    /**
     * 按JSON格式输出
     *
     * @param obj
     * @throws JsonProcessingException
     */
    private static void prettyPrint(Object obj) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        System.out.println(s);
    }


}


@Data
@AllArgsConstructor
class Person {
    private String name;
    private Integer age;
}

@Getter
class MyList<T> {
    private List<T> list = new ArrayList<>();

    public boolean add(T t) {
        return list.add(t);
    }

    /**
     * 给MyList传递具体的判断规则,然后MyList把内部现有符合判断(true)的元素集返回
     * @param predicate
     * @return
     */
    public MyList<T> filter(Predicate<T> predicate){
        MyList<T> filteredList = new MyList<>();

        for (T t : list) {
            if (predicate.test(t)) {
                // 收集判断为true的元素
                filteredList.add(t);
            }
        }

        return filteredList;
    }

    /**
     * 把MyList中的List<T>转为List<R>
     *
     * @param mapper
     * @param <R>
     * @return
     */
    public <R> MyList<R> map(Function<T, R> mapper) {
        MyList<R> mappedList = new MyList<>();

        for (T t : list) {
            mappedList.add(mapper.apply(t));
        }

        return mappedList;
    }

}

/**
 * 定义一个Predicate接口,名字无所谓
 *
 * @param <T>
 */
@FunctionalInterface
interface Predicate<T> {
    /**
     * 定义了一个test()方法,传入任意对象,返回true or false,具体判断逻辑由子类实现
     *
     * @param t
     * @return
     */
    boolean test(T t);
}


/**
 * 定义一个Function接口,名字无所谓
 *
 * @param <E>
 * @param <R>
 */

@FunctionalInterface
interface Function<E, R> {
    /**
     * 定义一个apply()方法,接收一个E返回一个R。也就是把E映射成R
     *
     * @param e
     * @return
     */
    R apply(E e);
}

看不懂没关系,感受一下即可。

下一篇会带着大家一步步分析上面的代码是怎么写出来的。

正所谓画龙画虎难画骨,山寨Stream API毕竟只是山寨版。

MyList虽然很像Stream API,但本质还是对List进行外部迭代,而正版的Stream API是先产生Stream流,再通过流迭代,属于内部迭代。两者其实存在本质区别。

本文只是借助这个例子切入Stream API的学习,你们也不可能在实际项目中放着正版Stream API不用,而拷贝我的山寨版。

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值