美文网首页
java函数式编程

java函数式编程

作者: 我是上帝可爱多 | 来源:发表于2017-08-29 09:12 被阅读30次

    今天我们来学习一下java8的新语法 ,有前端基础的同学看起来会更轻松。

    1 stream

    Java 8 中引入了流(Stream)的概念,这个流和以前我们使用的 IO 中的流并不太相同。
    假设我们有一个 List 包含一系列的 Person,Person 有姓名 name 和年龄 age 连个字段。现要求这个列表中年龄大于 20 的人数。
    通常按照以前我们可能会这么写:

    long count = 0;
    for (Person p : persons) {
        if (p.getAge() > 20) {
            count ++;
        }
    }
    

    但如果使用 stream 的话,则会简单很多:

    long count = persons.stream()
                        .filter(person -> person.getAge() > 20)
                        .count();
    
    count.forEach((item) -> print item.name)
    

    我们在这些java8的新式写法中看到了es6的身影,原谅我是一个前端gou。。。

    我们还能想到mapreduce这种在前端里面在为平常的操作了。

    List<String> collected = Stream.of("a", "b", "hello")
                                   .map(string -> string.toUpperCase())
                                   .collect(toList());
    assertEquals(asList("A", "B", "HELLO"), collected);
    

    请原谅我实在编不下去了,我只想用代码说明一切。。。

    List<String> beginningWithNumbers = 
            Stream.of("a", "1abc", "abc1")
                  .filter(value -> isDigit(value.charAt(0)))
                  .collect(toList());
    assertEquals(asList("1abc"), beginningWithNumbers);
    

    但是我目前为止还没发现js里面有合并的方法

    List<Integer> together = Stream.of(asList(1, 2), asList(3, 4))
                                   .flatMap(numbers -> numbers.stream())
                                   .filter(item -> item%2 == 0)
                                   .collect(toList());
    assertEquals(asList(2, 4), together);
    

    从这里可以看出flatMap是把2个collection合并为一个流。

    以前我们在java7进行比较排序的时候,一般是采用

    List<String> list = Arrays.asList("I", "love", "you", "too");
    Collections.sort(list, new Comparator<String>(){// 接口名
        @Override
        public int compare(String s1, String s2){// 方法名
            if(s1 == null)
                return -1;
            if(s2 == null)
                return 1;
            return s1.length()-s2.length();
        }
    });
    

    原始的Comparator接口是这个样子的

    public  interface  Comparable<T>{
            public  int compareTo(T  o);
    }
    

    上述代码通过内部类重载了Comparator接口的compare()方法,实现比较逻辑。采用Lambda表达式可简写如下:

    List<String> list = Arrays.asList("I", "love", "you", "too");
    Collections.sort(list, (s1, s2) ->{// 省略参数表的类型
        if(s1 == null)
            return -1;
        if(s2 == null)
            return 1;
        return s1.length()-s2.length();
    });
    

    我们在了解了lambada表达式后这样写更方便

    List<Integer> list = Lists.newArrayList(3, 5, 2, 9, 1);
    int maxInt = list.stream()
                     .max(Integer::compareTo)
                     .get();
    int minInt = list.stream()
                     .min(Integer::compareTo)
                     .get();
    assertEquals(maxInt, 9);
    assertEquals(minInt, 1);
    

    下面给大家展示一个更为熟悉的例子

    int result = Stream.of(1, 2, 3, 4)
                       .reduce(0, (acc, element) -> acc + element);
    assertEquals(10, result);
    

    注意 reduce 的第一个参数,这是一个初始值。0 + 1 + 2 + 3 + 4 = 10。

    我们来看下下面这段代码

    @Test  
    public void convertTest() {  
        List<String> collected = new ArrayList<>();  
        collected.add("alpha");  
        collected.add("beta");  
        collected = collected.stream().map(string -> string.toUpperCase()).collect(Collectors.toList());  
        System.out.println(collected);  
    }  
    

    改造成如下写法

    @Test  
    public void convertTest() {  
        List<String> collected = new ArrayList<>();  
        collected.add("alpha");  
        collected.add("beta");  
        collected = collected.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));//注意发生的变化  
        System.out.println(collected);  
    }  
    

    我们在js中对一个数组可以随意进行map,filter,reduce等操作,但是在java8中不行。

    int sumSize = Stream.of("Apple", "Banana", "Orange", "Pear")
                        .parallel()
                        .map(s -> s.length())
                        .reduce(Integer::sum)
                        .get();
    assertEquals(sumSize, 21);
    

    我们可以看到是在用了parallel()之后才可以进行并行流操作。

    可以自己把下面代码在ide中运行看一下

    public class Hello {
        Runnable r1 = () -> { System.out.println(this); };
        Runnable r2 = () -> { System.out.println(toString()); };
        public static void main(String[] args) {
            new Hello().r1.run();
            new Hello().r2.run();
        }
        public String toString() { return "Hello Hoolee"; }
    }
    

    会输出2次Hello Hoolee。

    请原谅我必须给大家还原一下事情的真相。

    // 使用迭代器删除列表元素
    ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
    Iterator<String> it = list.iterator();
    while(it.hasNext()){
        if(it.next().length()>3) // 删除长度大于3的元素
            it.remove();
    }
    

    现在使用removeIf()方法结合匿名内部类,我们可是这样实现:

    // 使用removeIf()结合匿名名内部类实现
    ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
    list.removeIf(new Predicate<String>(){ // 删除长度大于3的元素
        @Override
        public boolean test(String str){
            return str.length()>3;
        }
    });
    

    使用lambada表达式

    ArrayList<String> list = new ArrayList<>(Arrays.asList("I", "love", "you", "too"));
    list.removeIf(str -> str.length()>3); // 删除长度大于3的元素
    

    看一下如何进行字符串拼接。

    // 使用Collectors.joining()拼接字符串
    Stream<String> stream = Stream.of("I", "love", "you");
    String joined = stream.collect(Collectors.joining());// "Iloveyou"
    String joined = stream.collect(Collectors.joining(","));// "I,love,you"
    String joined = stream.collect(Collectors.joining(",", "{", "}"));// "{I,love,you}"
    

    我们下面来看看如何自定义函数接口

    / 自定义函数接口
    @FunctionalInterface
    public interface ConsumerInterface<T>{
        void accept(T t);
    }
    

    ConsumerInterface<String> consumer = str -> System.out.println(str);

    class MyStream<T>{
        private List<T> list;
        ...
        public void myForEach(ConsumerInterface<T> consumer){// 1
            for(T t : list){
                consumer.accept(t);
            }
        }
    }
    MyStream<String> stream = new MyStream<String>();
    stream.myForEach(str -> System.out.println(str));// 使用自定义函数接口书写Lambda表达式
    

    最后给大家讲一讲optional,Optional是Java8提供的为了解决null安全问题的一个API。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。

    public static String getName(User u) {
        if (u == null)
            return "Unknown";
        return u.name;
    }
    
    public static String getName(User u) {
        return Optional.ofNullable(u)
                        .map(user->user.name)
                        .orElse("Unknown");
    }
    

    这种写法是不是看起来更优雅。

    这样才是正确使用Optional的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。看一段代码:

    public static String getChampionName(Competition comp) throws IllegalArgumentException {
        if (comp != null) {
            CompResult result = comp.getResult();
            if (result != null) {
                User champion = result.getChampion();
                if (champion != null) {
                    return champion.getName();
                }
            }
        }
        throw new IllegalArgumentException("The value of param comp isn't available.");
    }
    
    public static String getChampionName(Competition comp) throws IllegalArgumentException {
        return Optional.ofNullable(comp)
                .map(c->c.getResult())
                .map(r->r.getChampion())
                .map(u->u.getName())
                .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
    }
    

    相关文章

      网友评论

          本文标题:java函数式编程

          本文链接:https://www.haomeiwen.com/subject/zqzjdxtx.html