久闻Java8 Stream
API大名,在Youtube上看了Venkat关于它的一个讲座 ,初步体会到了它的魅力;之后打算把《Efficient Java》那一章也看了,但是不知道怎么的,看自闭了,直接颓废了一天半555555,后面有机会再二刷吧
函数式编程就是将一个大的问题拆分成一小步一小步,每一步的职责分明,函数是一等公民,可以作为参数;在JavaScript中进行函数式编程非常方便,es6中对数组处理 map
,reduce
, foreach
等函数,而且可以方便地将函数作为参数传入到另一个函数中,也可以作为函数的返回值,非常经典的就是callback了;使用过前端工程化工具gulp
之后就觉得它的pipeline非常地优雅,使用第三方插件只需要把它封装的函数写在 pipe()
函数中就可以了,一连串 pipe
下来最后得到最终结果;在java8中对这些特性做到了很好的支持
问题一:求素数 普通的做法就是写一个for循环
1 2 3 4 5 6 7 8 private static boolean isPrime (final int data) { for (int i = 2 ; i < data; i++) { if (data % i == 0 ) { return false ; } } return data > 1 ; }
这里,那个for
循环和需要解决的问题几乎没关系,但是却占去了大量的空间。Venkat说,代码应该是可以让别人一目了然的,是poem,而不是puzzle;而且,比较一下 Stream 的第一种写法
1 2 3 4 5 private static boolean isPrime (final int data) { return data > 1 && IntStream.range(2 , data) .noneMatch(index -> data % index == 0 ); }
使用 IntStream.range(2, data)
代替for循环,使用 noneMatch
让代码意图让人一目了然;但是 noneMatch
中的代码还是不能让人一眼就看出意图;那就在封装一层呗,将其作为参数传入
1 2 3 4 5 6 private static boolean isPrime (final int data) { Predicate<Integer> isDivisible = divistor -> data % divistor == 0 ; return data > 1 && IntStream.range(2 , data) .noneMatch(isDivisible::test); }
虽然没有上一个版本简洁,但是可读性强了一些
问题二:求整数List中第一个大于3的偶数的两倍值 1 2 3 4 5 6 7 8 9 10 private static int task (List<Integer> numbers) { int result = 0 ; for (int number : numbers) { if (number > 3 && number % 2 == 0 ) { result = number*2 ; break ; } } return result; }
那如何用stream api采用函数式编程方式编写呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private static int task (List<Integer> numbers) { return numbers.stream() .filter(isGreaterThan(3 )) .filter(Main::isEven) .findFirst() .map(e -> e * 2 ) .orElse(0 ); } private static boolean isEven (Integer integer) { return integer % 2 == 0 ; } private static Predicate<Integer> isGreaterThan (int pivot) { return number -> number > pivot; }
问题三:整数List求和,可设置筛选条件 普通的解法这里就不写了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static void main (String[] args) { List<Integer> value = Arrays.asList(1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ); System.out.println(totalValue(value, v -> true )); System.out.println(totalValue(value, Main::isEven)); } public static int totalValue (List<Integer> integers, Predicate<Integer> selector) { return integers.stream() .filter(selector) .reduce(0 , Math::addExact); } private static boolean isEven (Integer integer) { return integer % 2 == 0 ; }
问题四:对文本文件数据进行处理 文本文件如下
1 2 3 4 5 AA,aaa,2312,423,adas BB,dad,rwqr,fs,FDSFDS DSAFSD,FDSFDSA,EWR,WE aa BB,dsafds,fsd
将其存在Map中,每行以逗号为分割符,第一个字符作为key,value为分割好的字符数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public static void main (String[] args) throws Exception { Function<String, Function<String, String[]>> spiltString = spliter -> str -> str.split(spliter); Stream<String> lines = Files.lines(Paths.get("txt.txt" )); lines.map(spiltString.apply("," )) .collect(Collectors.toMap( x -> Integer.parseInt(x[0 ]), x -> x )) .forEach((k, v) -> { System.out.print(k + " " ); Arrays.stream(v) .map(str -> str + " " ) .forEach(System.out::print); System.out.println(); });
结果如下
1 2 3 4 5 1 1 aaa 2312 423 adas 2 2 dad rwqr fs FDSFDS 3 3 FDSFDSA EWR WE 4 4 5 5 dsafds fsd
扩展