java函数式编程
今天我们来学习一下java8的新语法 ,有前端基础的同学看起来会更轻松。 1 streamJava 8 中引入了流(Stream)的概念,这个流和以前我们使用的 IO 中的流并不太相同。 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}" 我们下面来看看如何自定义函数接口 / 自定义函数接口@FunctionalInterfacepublic 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.")); } 作者:我是上帝可爱多 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |