近况
好长时间没有更新博客了,这段时间中忙着找工作,忙着熟悉工作上的事,但这其实并不算理由吧
真正让我没有更新博客的原因是:我更加清楚的知道自己的方向并在为之努力,这种方向可能并不是
单纯技术上的学习,更多的是对项目流程上的把控和认识,之前实习时候带过我的凯谟哥说的没错
业务确实比技术更重要吧,以前的我专注技术提升,实际上在公司中学习的并不只有技术,以有涯对无涯,殆矣
当然我并不是鼓吹无需掌握技术,而是觉得应该有这方面的意识,开发方向的技术学习当然也需要学习,
但无需深究,养活一个公司的永远是订单,而不是内部使用多高明的框架。
近期目标:
- 我需要尽快熟悉公司真正的业务流程,我现在所在的公司哪里都好,就是有一点不好就是
项目上开发文档几乎没有,开发文档不仅仅包括api接口内容,开发文档应该包括对整体项目概述,
对业务模块和模块间联系的说明和阐述,对数据库表和表之间的关联关系解释,对业务流程有说明和相应的概括和细化
不然新人学习成本太大,培养熟悉公司业务的员工是一大难事,一旦老员工离职对于初创企业来说是一个不小的打击。 - 8月开始学习关于软考中软件设计师的内容,软件中级并不算简单,考试时间在11月份,准备3个月时间,
一定要拿下这场考试,关于考试的资料,考试应该学习的网课内容,我已经收集完毕了 - 学习公司经常使用的技术栈,计算机开发中有非常多的技术,学习的内容非常多,我觉得还是应该跟从公司
技术栈来学习更好,经常使用的技术优先度应该要更高,这样学习的不仅是基础使用,而是实际场景中的解决方案
言归正传,今天学习的内容是函数式接口和Stream流的使用,函数式接口之前在《聊聊多线程(二)》博客中提过
今天重新回顾一下,Stream流是我一直想要学习但没有学习的内容,因为学习过js中的map,filter函数后
我发现两者真的很像,想来基础使用并不难,便一直拖到现在。下面是本章内容
函数式接口
函数式接口的概念
函数式接口指的是只有一个抽象方法的接口,例如以前学习的Runnable接口,Callable接口,Comparator接口
下面是java8之前函数式接口:而在java8又新增了一些新的函数式接口,它们都在`java.util.function`包下, 主要有下面这些函数式接口,当然还有这些函数式接口的衍生接口就省略了
1,Consumer<T> 代表了接受一个输入参数并且无返回的操作 2,Function<T,R> 接受一个输入参数,返回一个结果。 3,Predicate<T> 接受一个输入参数,返回一个布尔值结果。 4,Supplier<T> 无参数,返回一个结果。 5,UnaryOperator<T> 接受一个参数为类型T,返回值类型也为T。
函数式接口的基本使用
函数式接口一般当做参数使用,以往我们方法参数都是一些基本类型,包装类型,对象类型,
那方法的参数可不可以是其他方法呢?当然也是可以的,举个例子//这里Thread对象在创建的时候,接受一个Runnable接口的实现类作为参数 new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }); //你也可以将匿名实现类改写成lambda的形式,你看,这像不像是run方法作为了参数 new Thread(()->{ System.out.println(Thread.currentThread().getName()); }); //同样是使用lambda,我们也可以这么写,上面案例只是没特别说Thread参数需要是Runnable接口类型 //这里把lambda所表示的类型写出来,表明,这个lambda表达式表示Runnable类型的 Runnable runnable = ()->{ System.out.println(Thread.currentThread().getName()); }; new Thread(runnable); //同样的,forEach方法参数可以接收一个Consumer接口实现类作为参数,而匿名Consumer接口实现类 //可以使用lambda代替使用,当然这里也没有说明foreach要的是什么参数类型 List list =Arrays.asList(1,2,3,4,5); list.forEach((num)->{ System.out.println("你是:"+num); }); //我们同样可以显示把接口类型写出来,不过常用的方式是上面这种方式 List list =Arrays.asList(1,2,3,4,5); Consumer consumer = (num)->{ System.out.println("你是:"+num); }; list.forEach(consumer); /* 看到这你应该知道了,其实函数式接口不管是Runnable接口还是Consumer接口 通常都使用lambda方式表示,所以看起来就像是方法作为参数一样 函数式最主要的特点是:函数式接口的功能实现由调用者实现,而不是编写者, 例如线程池的拒绝策略就是由调用者实现而不是编写者。这里我们使用线程池是调用者, 写线程池代码的人就是编写者 下面同样是一个comsumer的简单使用,可能例子不恰当 */ public class Test { public static void main(String[] args) { //我调用方法,我自己实现如何处理每一个数据 consumerTest((num)->{ System.out.println("第"+num); }); } public static void consumerTest(Consumer<Integer> consumer){ List list =Arrays.asList(1,2,3,4,5); list.forEach(consumer); } }
相关博客
关于函数式接口的其他接口的具体使用,可以看看其他博客
别人写的比我详细,我就不重复写了
Stream流
Stream流用来处理集合中的一些常见操作,例如去重,排序,过滤,遍历,查找,统计等等
因为是链式编程,数据像水流一样经过一个个操作处理,所以被叫做Stream流
因为网上已经有非常多的类似博客,所以我这里只是简单记录一下吧
Stream生命周期及各时期方法的使用
Stream生命周期或者说使用流程如下图:
各个方法使用方式
stream(),Stream.of方法,Stream.iterate方法,Stream.generate方法,都可创建stream流
//利用Stream.of方法创建流 Stream<String> stream = Stream.of("hello", "world", "Java8"); stream.forEach(System.out::println); System.out.println("##################"); //利用Stream.iterate方法创建流 Stream.iterate(10, n -> n + 1) .limit(5) .collect(Collectors.toList()) .forEach(System.out::println); System.out.println("##################"); //利用Stream.generate方法创建流 Stream.generate(Math::random) .limit(5) .forEach(System.out::println); System.out.println("##################"); //从现有的集合中创建流 List<String> strings = Arrays.asList("hello", "world", "Java8"); String string = strings.stream().collect(Collectors.joining(",")); System.out.println(string);
filter(),map(),flatMap(),limit(n),skip(n),concat(),distinct(),sorted(),peek(),reduce,操作stream
************************************************************************* //map()和flatMap,map用于一对一转换,flatMap用于一对多转换 List<String> ids = Arrays.asList("205", "105", "308", "469", "627", "193", "111"); // map List<User> results = ids.stream() .map(id -> { User user = new User(); user.setId(id); return user; }) .collect(Collectors.toList()); /* 2022-12-23更新 1.如果没有collect方法,则map中对ids集合元素进行的操作不会对ids集合产生效果, 2.如果collect方法返回results集合,则这个集合与ids不相等,至于是不是深拷贝不清楚 并且源集合ids同样被修改了,ids集合数据与results集合数据保持一致。 3.使用map并不会打乱集合中元素的顺序,而parallelStream会打乱集合元素顺序 */ //flatmap,现有一个句子列表,需要将句子中每个单词都提取出来得到一个所有单词列表 List<String> sentences = Arrays.asList("hello world","Jia Gou Wu Dao"); List<String> results = sentences.stream() .flatMap(sentence -> Arrays.stream(sentence.split(" "))) .collect(Collectors.toList()); /* 区别在于,map只能将流中元素转成其他类型,但不能将流中元素再次转为stream流 flatmap,就是匹配流中每一个元素,还可对这些元素继续操作,将元素内部拆分出来 */ ************************************************************************* //concat,两个流相连接用concat,三个以上用flatmap //两个流的连接 Stream<String> first = Stream.of("sihai", "sihai2", "sihai3"); Stream<String> second = Stream.of("sihai4", "sihai5", "sihai6"); Stream<String> third = Stream.of("siha7", "sihai8", "sihai9"); Stream<String> concat = Stream.concat(first, second); //多个流的连接 Stream<String> stringStream = Stream.of(first, second, third).flatMap(Function.identity()); ************************************************************************* //limit,截取前几个流中元素 //skip,跳过前几个流中元素 //distinct,给流中元素去重 //sorted,排序 //filter,过滤,返回值为false过滤掉 List<String> ids = Arrays.asList("205","10","308","49","627","193","111", "193"); List<Dept> results = ids.stream() .filter(s -> s.length() > 2) .distinct() .map(Integer::valueOf) .sorted(Comparator.comparingInt(o -> o)) .limit(3) .map(id -> new Dept(id)) .collect(Collectors.toList()); ************************************************************************* /* peek,peek和foreach,都可以用于对元素进行遍历然后逐个的进行处理。 但根据前面的介绍,peek属于中间方法,而foreach属于终止方法。这也就意味着peek只能作为管道中途 的一个处理步骤,而没法直接执行得到结果,其后面必须还要有其它终止操作的时候才会被执行; 而foreach作为无返回值的终止方法,则可以直接执行相关操作。 */ List<String> sentences = Arrays.asList("hello world","Jia Gou Wu Dao"); // 演示点1: 仅peek操作,最终不会执行 System.out.println("----before peek----"); sentences.stream().peek(sentence -> System.out.println(sentence)); System.out.println("----after peek----"); // 演示点2: 仅foreach操作,最终会执行 System.out.println("----before foreach----"); sentences.stream().forEach(sentence -> System.out.println(sentence)); System.out.println("----after foreach----"); // 演示点3: peek操作后面增加终止操作,peek会执行 System.out.println("----before peek and count----"); sentences.stream().peek(sentence -> System.out.println(sentence)).count(); System.out.println("----after peek and count----"); //结果 ----before peek---- ----after peek---- ----before foreach---- hello world Jia Gou Wu Dao ----after foreach---- ----before peek and count---- hello world Jia Gou Wu Dao ----after peek and count---- ************************************************************************* //reduce,规约操作,和js中reduce一样,操作流中前后两个元素并将结果赋值给下一个元素,依次操作 @Test public void testReduce2() { int sum = IntStream.range(1, 20) .reduce((x, y) -> x + y) .orElse(0); System.out.println(sum); int sum2 = IntStream.range(1, 20) .reduce(0, (x, y) -> x + 2 * y); System.out.println(sum2); int sum3 = IntStream.range(1, 20) .reduce(0, Integer::sum); System.out.println(sum3); } //结果 190 380 190
count,max,min,summaryStatistics,findFirst,findAny,anyMatch,allMatch,noneMatch,collect,
最后一次操作流的方法,终止Stream//count,统计stream操作后剩余的元素个数 List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); System.out.println(ids.stream().filter(s -> s.length() > 2).count()); ************************************************************************* //max,min,summaryStatistics List<Integer> integers = Arrays.asList(1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 2, 2, 2, 2); Optional<Integer> max1 = integers.stream().max(Integer::compare); Optional<Integer> max2 = integers.stream().min(Integer::compare); System.out.println(max1.get()); System.out.println(max2.get()); //反向排序 Optional<Integer> var = list.stream().max(Comparator.reverseOrder()); if (var.isPresent()) { System.out.println(var.get()); } else { System.out.println("-1"); } DoubleSummaryStatistics statistics = DoubleStream.generate(Math::random) .limit(1000) .summaryStatistics(); ************************************************************************* /* findFirst,findAny findFirst方法返回流中的第一个元素的Optional,而findAny方法返回流中的某个元素的 Optional。 */ String[] strings = {"hello", "sihai", "hello", "Java8"}; Optional<String> first = Arrays.stream(strings) .findFirst(); System.out.println(first.get()); Optional<String> any = Arrays.stream(strings).findAny(); System.out.println(any.get()); ************************************************************************* /* anyMatch,allMatch,noneMatch anyMatch(任何一个元素匹配,返回 true) allMatch(所有元素匹配,返回 true) noneMatch(没有一个元素匹配,返回 true) */ boolean b = Stream.of(1, 2, 3, 4, 5, 10) .anyMatch(x -> x > 5); boolean b2 = Stream.of(1, 2, 3, 4, 5, 10) .allMatch(x -> x > 5); boolean b3 = Stream.of(1, 2, 3, 4, 5, 10) .noneMatch(x -> x > 5); ************************************************************************* /* collect 对集合数据的处理场景更多的是获取一个集合类的结果对象,比如List、Set或者HashMap等。 这里就需要collect方法出场了,它可以支持生成如下类型的结果数据: 1,一个集合类,比如List、Set或者HashMap等 2,StringBuilder对象,支持将多个字符串进行拼接处理并输出拼接后结果 3,一个可以记录个数或者计算总和的对象(数据批量运算统计) */ //1,生成集合 public void testCollectStopOptions() { List<Dept> ids = Arrays.asList(new Dept(17), new Dept(22), new Dept(23)); // collect成list List<Dept> collectList = ids.stream().filter(dept -> dept.getId() > 20) .collect(Collectors.toList()); System.out.println("collectList:" + collectList); // collect成Set Set<Dept> collectSet = ids.stream().filter(dept -> dept.getId() > 20) .collect(Collectors.toSet()); System.out.println("collectSet:" + collectSet); // collect成HashMap,key为id,value为Dept对象 Map<Integer, Dept> collectMap = ids.stream().filter(dept -> dept.getId() > 20) .collect(Collectors.toMap(Dept::getId, dept -> dept)); System.out.println("collectMap:" + collectMap); } //结果 collectList:[Dept{id=22}, Dept{id=23}] collectSet:[Dept{id=23}, Dept{id=22}] collectMap:{22=Dept{id=22}, 23=Dept{id=23}} //2,生成拼接字符串,例如将一个List或者数组中的值拼接到一个字符串里并以逗号分隔开 public void testCollectJoinStrings() { List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193"); String joinResult = ids.stream().collect(Collectors.joining(",")); System.out.println("拼接后:" + joinResult); } //结果,拼接后:205,10,308,49,627,193,111,193 //3,数据批量数学运算,使用collect生成数字数据的总和信息 public void testNumberCalculate() { List<Integer> ids = Arrays.asList(10, 20, 30, 40, 50); // 计算平均值 Double average = ids.stream().collect(Collectors.averagingInt(value -> value)); System.out.println("平均值:" + average); // 数据统计信息 IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value)); System.out.println("数据统计信息: " + summary); } //结果 平均值:30.0 总和: IntSummaryStatistics{count=5, sum=150, min=10, average=30.000000, max=50}
推荐文章