Java8的记录与思考
Collection主要是为了存储和访问数据,而Stream则主要用于描述对数据的计算
需求的本质变化是行为在变,而行为在代码里面体现出的是方法/函数,而不是对象,所以把“可变的部分”抽象/分离,是个不错的主意。
所以Java8把方法都变成了参数,可以进行抽象和分离了。
行为参数化就是可以帮助你处理频繁变更的需求的一种软件开发模式。
Function: T apply(T t)
Predicate: boolean test(T t)
Consumer: void accept(T t)
Supplier: T get()
stream 可以声明式的表达做什么,而不用说明如何去实现,不暴露细节
流到底是什么呢?简短的定义就是“从 支持数据处理操作的源 生成的元素序列”。
集合和流的区别:
集合是数据结构,所以它的主要目的是以特定的时间/空间复杂度存储和访问元素(如ArrayList 与 LinkedList)。
但流的目的在于表达计算。集合讲的是数据,流讲的是计算。
集合是存放于内存的,是有限的(集合.sise()),要提前准备好的。流是需要的时候再获取数据,可以处理无穷(素数流),实时性强。
!!!要想创建一个包含所有素数的集合,那是不可能的。
这就意味着这个初始化的工作难以完成,要用这个集合的人(消费端)永远也等不到这个集合。
流体现了按需获取的思想。
流只能被遍历一次。遍历的过程可以理解为被消费了的过程。
集合需要外部迭代,流则是内部迭代(内部迭代可以自动选择一种适合用户硬件的数据表示和并行实现)
流的操作:1)中间操作,2)终端操作
循环合并,短路操作
要思考stream类提供的方法的现实意义,比如它提供了min,但不提供sum,stream处理的是人,把人加起来是没什么意义的,而通过某个维度取min是有现实意义的。
为此:Stream API还提供了“原始类型流”特化(ntStream、DoubleStream和LongStream),专门支持处理数值流的方法。
xxx.stream().mapToInt返回IntStream而非Stream<Integer>,避免了Integer到int的拆箱。
“原始类型流”转化回“对象流”:Stream<Integer> stream = intStream.boxed();
如何区分没有元素的流和最大值真的是0的流呢?
对于三种原始流特化,也分别有一个Optional原始类型特化版本:OptionalInt、OptionalDouble和OptionalLong
数据,可以存储、访问和计算
Stream API提供了两个静态方法来从函数生成流:Stream.iterate和Stream.generate。这两个操作可以创建所谓的无限流。
收集器的重要性。
分组:根据某个属性的值进行的
分区:可以根据谓词(分组函数)进行分组的
多属性分组:https://www.jianshu.com/p/dd5121c8fa89
多级分组:两级:Map<key,Map<key,list>>
再次强调“Stream接口可以让你以声明性方式处理数据集”
java7之前,并行处理数据集的步骤:
1)明确的把数据分成几部分
2)为每个部分分配独立的线程
3)想办法避免竞争
4)等待所有线程处理完成之后进行合并
顺序流-》并行流
并行流就是一个把内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
共享可变状态会影响并行流以及并行计算
对设计经验的归纳总结被称为设计模式。可重用的解决方案。
策略模式;
模版方法;
观察者模式;
责任链模式;
二进制级的兼容:比如,为接口添加一个方法就是二进制级的兼容,这种方式下,如果新添加的方法不被调用,接口已经实现的方法可以继续运行,不会出现错误。
源代码级的兼容:源代码级的兼容性表示引入变化之后,现有的程序依然能成功编译通过。比如,
向接口添加新的方法就不是源码级的兼容,因为遗留代码并没有实现新引入的方法,所以它们
无法顺利通过编译。
函数行为的兼容:程序接受同样的输入能得到同样的结果。
默认方法是一种以源码兼容方式向接口内添加实现的方法。
采用防御式检查减少 NullPointerException,不具备扩展性,同时还牺牲了代码的可读性。
如何对“什么值都不是”进行建模?
Optional<T>的设计哲学,允许为空,即隐藏了空带来的潜在问题,如果不允许为空则要暴露出来。
并发和并行的区别:
1)并发指的是在单个处理器中,不断切换时间片处理多个任务,看起来像并行多任务处理,其实不然,这种方式可以把单个处理器利用到极致。
2)并行指的是多个任务分配到多个处理器中处理,理想的情况下是任务与处理器一对一,这样处理的效率最高,可以充分利用多核机器的资源。
程序员往往渴望加入的是一支“30%的时间在写代码,而70%的时间在喝着咖啡讨论着如何将产品做好”的团队。软件工作应该成为一项技术和艺术融合的高智力活动,而XX经理应该是一个高度理解质量、范围和进度客观规律的明白人。
如何用异步的方式使用同步的API
重剑无锋、大巧不工(真正的剑技不是要依靠剑锋,而是个人的修行;真正的技巧不一定是刻意为之,力求工整的,也不是工匠的艺术,而是蕴涵天赋、自然而成的)
有些历史旧账如果不牺牲前向兼容性是无法解决的。
解析日期或时间的DateFormat方法就只在Date类里有。
DateFormat方法也有它自己的问题。比如,它不是线程安全的。这意味着两个线程如果尝
试使用同一个formatter解析日期,你可能会得到无法预期的结果。
时间分为两大类:给人的,给机器的
人:LocalDate,LocalTime,LocalDateTime
机器:Instant
Duration类:衡量秒级的短暂时间周期
Period类:衡量日、月、年级别的跨越较长的时间周期
Duration threeMinutes = Duration.of(3, ChronoUnit.MINUTES);
体现了值与单位度量的分离设计理念。
DateTimeFormatter
String -> Date,用.parse
Date -> String,用.format
虽然在编码的过程中没有显式的使用时区,但在jvm运行的时候是默认带上当前系统默认的时区的。
如果一个方法既不修改它内嵌类的状态,也不修改其他对象的状态,使用return返回所有的计算结果,那么我们称其为纯粹的或者无副作用的
简而言之,副作用就是函数的效果已经超出了函数自身的范畴。
不可变对象是这样一种对象,它们一旦完成初始化就不会被任何方法修改状态。
声明式编程-》函数式编程。
是否有真正的生产系统能够以不可变对象进行构建。
解决问题像问题陈述(做什么),而不像指令操作过程那样(怎么做)。
采用这种“要做什么”风格的编程通常被称为声明式编程。
当谈论“函数式”时,我们想说的其实是“像数学函数那样——没有副作用”。
纯粹的函数式编程,完全没有副作用,就像Math里的函数一样,一个输入对一个输出,只计算,不改变任何东西。
函数式编程,有副作用,但不暴露在外,不被调用者所感知。
我们的准则是,被称为“函数式”的函数或方法都只能修改本地变量。
除此之外,它引用的对象都应该是不可修改的对象。
为什么在Java中,没有像数据库查询式的语言去操作数据呢?
开发企业级应用。有什么特点?
当一门技艺被冠以经典之名时,它的创新才刚刚开始。比如经典的Java编程。