《Java 8实战》是一本由厄马(Raoul-Gabriel Urma) / 弗斯科(Mar著作,人民邮电出版社出版的平装图书,本书定价:CNY 79.00,页数:349,文章吧小编精心整理的一些读者的读后感,希望对大家能有帮助。
《Java 8实战》读后感(一):全面介绍Java 8的核心特性
我是先读的《Java 8函数式编程》再读该书,总体是两本书的质量都非常高,五星推荐!
1.相比于《Java 8函数式编程》注重于介绍函数式编程相关,该本覆盖的Java 8特性更全面,在书中能看到对Optional、CompletableFuture、新的日期API的介绍;
2.该书对Stream的收集器介绍得更为全面和具体;
3.Java 8的函数式编程一定是未来Java编程的方向,它所带来的改变能和Java 5相提并论,哪怕你的项目组采用的不是Java 8版本,也推荐一读。Java 8带来的编程体验的提升,只有你试过了才知道。
《Java 8实战》读后感(二):Java8实战读后感
背景介绍:阅读过Java编程思想,深入理解JVM,并发编程实战,一半Effective Java,无函数式编程的经验
阅读本书前面章节时(1~3章),曾觉得较为简单,以前已经习惯了匿名内部类的写法,在我看来Lambda及方法引用只是个匿名内部类的语法糖,虽然提供了函数式编程的思想,使开发人员能更清晰的编写代码(对于熟练开发人员来说匿名类和Lambda的理解难易程度一致,但是使用方法引用代替Lambda还是比较清晰的),对于性能没有太大的影响
但是从4~7章,介绍stream开始,
1.使用流代替集合,除声明式编程易于理解外,减少遍历次数,提高性能.
2.并行流封装所有底层实现细节,减少开发难度
3.并行处理数据就不得不说到同步,而后介绍到不可变对象(在阅读本书之前曾阅读了并发编程实战,被虐的要死,再次看本书,两相印证,加深了对并发编程的理解,本书中的概念:不可变,函数式编程,引用透明性都可以较为轻松的理解)
CompletableFuture;取代Future,和其他新特性完美结合
其他如:default方法,Optional,新的日期和时间API都是一些便于开发人员的小改动
对我来说:本书前面的内容较易理解,越到后面越是一些高级的特性,由易至难(刚好是我如今这个阶段可以掌握却又有提高的书籍),尤其是书中第四部分:超越Java8,打开了新的思路
《Java 8实战》读后感(三):编程语言的作用之---- stream流式编程
1.编程语言的目的是 操作 值
基于数据的编程,为了操作值,会发明,数据类型(对应的存储方式),逻辑计算符号(来跳转和选择),数据结构,来合适的存储一些列的有格式的值
2.多核cpu与并行
如果一个进程一个cpu,多个并行有可能会冲突
但如果一个 程序的执行是 在 多个cpu呢,把代码分段,是否也是 防止冲突的一种方法呢,如下
3. Optional T 类,有类型的值,有可能是没有值null,方便处理
4.函数式编程,或者书 管道处理,stream流处理,为什么要这样处理数据?
方便过滤数据,写出多个过滤数据的方法,用的时候,只要 加后者减,就可以 ,而不要 重复写代码
5.代码与进程,线程
一段代码,开始在cpu执行了,就是一个进程,这个代码执行的生命周期,就是这个进程的生命周期
线程是 大代码块的一段小 代码块,可以用不同的线程 执行不同的代码块
6.流stream 和 集合的区别
注意:流和迭代器一样,流只能遍历一次,遍历完了,我们就说这个流被消费了。
流是内部迭代,下一个数据是啥,只要有,就给你 ,一直到没有
集合是外部迭代
《Java 8实战》读后感(四):我的全部读书笔记+思想
Java 8的新特性可以帮助你:
1.使用Java 8可以减少冗长的代码,让代码更易于理解
2.通过方法引用和Stream API,代码会更加直观
使用 Java 8 重构现在代码 :
1.使用 Lambda 表达式取代匿名类
2.使用方法引用重构 Lambda 表达式
3.使用 Stream API 重构指令式的数据处理
Java 8 新特性总结:
● Lambda 表达式
● 行为化参数(Lambda 以及方法引用)
● Stream API (流) 高效率的集合操作
● CompletableFuture 优化并发接口
● Optional T 解决null指针异常
● Default 接口默认方法
● LocalDate 等..新的时间类
??书本最末的一些总结
命令式编程(编写代码,设计实现过程,处理不同的情况(异常,NULL,循环),获取结果)
函数式编程(通过代码告诉程序,我想要什么,然后拿到结果)
?? Java 8 的大方向和主要功能对现有代码的影响
方法引用就是让你根据已有的方法实现来创建Lambda表达式,当你需要使用方法引用时,目标引用放在分隔符 ::前,方法的名称放在后面,例如Apple :: getWeight就是引用了Apple类中定义的方法 getWeight,请记住,不需要括号,因为你没有实际调用这个方法,方法引用就是Lambda表达式 (Apple apple) - apple.getWeight() 的快捷写法
??对于Lambda表达式参数,尽量使用方法引用的写法(官方推荐)
//Lambda 写法
Function String, Integer stringToInteger = (String s) - Integer.parseInt(s);
iPredicate List String , String contains = (list, element) - list.contains(element);
// -- 方法引用
Function String, Integer stringToInteger2 = Integer::parseInt;
iPredicate List String , String contains2 = List::contains;
?? Lambda 表达式等效的方法引用写法栗子(练习题)
lambda编程就是方法参数化:让方法接受多种行为作为参数,并在内部使用,来完成不同的行为
??lambda的核心思想
3.10小结:
lambda表达式可以理解为一种匿名函数
lambda表达式可以让你简洁地传递代码
函数式接口,就是声明了一个抽象方法的接口
只有在接受函数式接口的地方才可以使用 lambda 表达式
java8自带常用函数式接口:java.util.function包,包括Predicate T ,Function T,R ...等
为了避免装箱操作,Predicate T 和Function T,R 等通用函数式接口的原始类型
??Lambda表达式,就是针对面向函数式接口方法作为参数的时候将方法体作为参数输入
treamAPI 允许以声明性方式处理数据集合,可以把它看成遍历数据集的高级迭代器。
此外流还可以透明睇并行处理,无需写任何多线程代码:
声明性---更简洁、更易读,可复合---更灵活,可并行--性能更好
流的使用一般包括三件事:
1、数据源(如集合)来执行
2、中间操作链,形成一条流的流水线
3、一个终端操作、执行流水线、并能生成结果
??StreamAPI的基本用户、基本概念
集合讲的是数据,Stream流讲的是计算
tream 所有操作都会返回另一个流,这样他们就形成一条流水线,最后通过collect,返回list结束
tream api 常用方法
anyMatch 接受 lambda,返回布尔值,用于判断集合
filter -- 接受lambda,从流中排除某些元素
map -- 接受lambda,讲元素转换为其他形式或提取信息
orted -- 接受Comparator 函数接口
limit -- 接受Int,截断流,限制返回条数
distinct -- 不显示重复
collect -- 将流转换为其他形式,通过 toList() 转为 list
//集合是生产生,流是消费者,流只能消费一次
??筛选集合、数组的好工具
tream库可以自动选择一种适合你硬件的数据表示和并行实现
而集合的迭代需要自己管理所有问题,还有和synchronized的艰苦斗争
??stream迭代可以最大化利用硬件,集合就有点过时
连接stream流的操作称为中间操作,关闭流的操作称为终端操作(中间操作一般都可以合并起来,在终端操作时一次性全部处理)
??stream自行选择最优的方法执行并行操作
tream API通过allMatch、 anyMatch、 noneMatch、findFirst和findAny方法提供这样的工具
??stream api对于数据的查找和匹配提供的一套API工具,和filter函数不一样,以上API工具都是提供boolean返回值用于判断,filter用于过滤集合
java.util.optional是一个容器类,用于表示一个值存在或不存在,用户避免和null相关的Bug
isPresent() 将在Optional包含值得时候返回true,否则返回false
ifPresent(Consumer T block) 会在值存在的时候执行给定的代码块
get() 会在值存在的时返回值,否则抛出一个NoSuchElement异常
orElse(T other) 会在值存在的时返回值,否则返回一个默认值
??新的容器类和一些新的调用方法
用Stream流8道题解答方法:
//交易员
Trader raoul = new Trader( Raoul , Cambridge
Trader mario = new Trader( Mario , Milan
Trader alan = new Trader( Alan , Cambridge
Trader brian = new Trader( Brian , Cambridge
//交易
List Transaction transactions = Arrays.asList(
ew Transaction(brian, 2011, 300),
ew Transaction(raoul, 2012, 1000),
ew Transaction(raoul, 2011, 400),
ew Transaction(mario, 2012, 710),
ew Transaction(mario, 2012, 700),
ew Transaction(alan, 2012, 950)
);
//1.找出2011年发生的所有交易,并按交易额排序
transactions.stream().filter(t - t.getYear() == 2011).sorted(Comparator.comparing(Transaction::getValue)).forEach(System.out::println);
//2.交易员都在哪些不同的城市工作过?distinct不显示重复数据
transactions.stream().map(t - t.getTrader().getName() + : + t.getTrader().getCity()).distinct().forEach(System.out::println);
//3.查找所有来自剑桥的交易员,并且按照姓名排序
transactions.stream().filter(t - t.getTrader().getCity().equals( Cambridge )).sorted((o1, o2) - o1.getTrader().getName().compareTo(o2.getTrader().getName())).map(t - t.getTrader().getName() + = + t.getTrader().getCity()).distinct().forEach(System.out::println);
//返回所有交易员的姓名字符创,按照字母排序
tring nameString = transactions.stream() .map(t - t.getTrader().getName()).distinct().sorted().reduce( , (n1, n2) - n1 + n2);
//有没有交易员是在Milan工作的 ?
// 查找 // 判断
// transactions.stream().filter(t - t.getTrader().getCity().equals( Milan )).map(t - t.getTrader().getName()).distinct().forEach(System.out::println);
oolean isMilan = transactions.stream().anyMatch(t - t.getTrader().getCity().equals( Milan ));
//打印在剑桥的交易员的所有交易额
transactions.stream().filter(t - t.getTrader().getCity().equals( Cambridge )).map(t - t.getValue()).forEach(System.out::println);
//所有交易中,交易额最高的是多少
transactions.stream().map(t - t.getValue()).reduce(0, Integer::max);
transactions.stream().mapToInt(Transaction::getValue).max();
//所有交易中,交易额最小的是多少
transactions.stream().reduce((t1, t2) - t1.getValue() t2.getValue() ? t1 : t2); //通过反复比较,找出最小的交易
transactions.stream().min(Comparator.comparing(Transaction::getValue));
transactions.stream().mapToInt(Transaction::getValue).min();
??使用stream流来操作集合真是得心应手,想要什么都能找到
tream流的创建不单针对集合,还可以从值序列,数组,文件来创建流,例如:
//由字符串创建流,转为大写循环输出
tream String stream = Stream.of( java8 , lambdas , a , in , action
tream.map(String::toUpperCase).forEach(System.out::println);
//由数组创建流,统计数组合计
int[] streamArray = {2,5,7,11,22,33};
Arrays.stream(streamArray).sum();
??stream api 可能改变所有java程序的写法
treams API可以表达复杂的数据处理查询。常用的流操作总结在表5-1中
可以使用filter、distinct、skip和limit对流做筛选和切片
可以使用map和flatMap提取或转换流中的元素
可以使用findFirst和findAny方法查找流中的元素,你可以用allMatch、noneMatch和anyMatch方法让流匹配给定的谓词
这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流
你可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素
流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法创建
??第二章节 Stream流的总结,大概了解,还需要时间去练习和消化其中内容,熟悉Stream流对Java编码方式都会有很大的改变,感觉Java8的函数式编程已经完全颠覆的以前的编码方式
函数式编程相对于指令式编程(Java 7前)的一个主要优势:你只需要指出希望的结果“做什么”,而不用操心执行的步骤,“如何做”,例如针对的集合,根据对象某个属性讲集合分组,函数编程代码如下:
Transaction是交易对象,根据Currency货币针对所有交易进行分组 (开发中很常见):
Map Currency, List Transaction mapCurrency = list.stream().collect(groupingBy(Transaction :: getCurrency))
还可以自定义逻辑,把逻辑作为Lambda参数,进行分组
ublic enum CaloricLevel { DIET, NORMAL, FAT }
Map CaloricLevel, List Dish dishesByCaloricLevel = menu.stream().collect( groupingBy(dish - {
if (dish.getCalories() = 400) return CaloricLevel.DIET;
else if (dish.getCalories() = 700) return
CaloricLevel.NORMAL;
else return CaloricLevel.FAT;
} ));
要实现多级分组,可以使用双参数版本Collectors.groupingBy工厂方法创建收集器
??如果不是应用比较广,自身对Java语言一直不是很有兴趣,因为语言太繁琐,很简单的功能要写很多的代码,函数式编程,让我开始对Java有些兴趣了,SQL也是函数式编程,终于开始觉得Java有点酷了
分区是分组的特殊情况,有一个布尔值作为分类函数,意味着分组Map的主键为Boolean,于是也最多可以分为2组,true是一组,false是一组
??分区有点像分组的简化,对于逻辑不是很复杂的分组,可以用分区
tream可以通过对收集源调用prarllelStream方法来把集合转换为并行流,并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流,这样一来,你就可以自动把给定操作的工作负荷分配给多核处理器的所有内核,让他们都忙起来
??stream 自带多线程处理方法,并且根据硬件自动优化,不需要自己实现复杂的多线程,对于CPU核心越来越多的现在,相比以前Java的单核处理效率有很大的提高
把顺序流转成并行流,从而让前面的函数归约过程(也就是求和)并行运行,对顺序流调用parallel()方法
并行编程很复杂,有时候甚至有点违反直觉,如果用的不对(比如采用了一个不易并行化的操作,如iterate),它甚至可能让程序的整体性能更差,所以在调用看似神器的 parallel 操作时,了解背后发生
(使用正确的数据结构然后使其并行工作能够保证最佳的性能)
??顺序流转并行流就是调用 parallel() 方法,多线程方法也不能乱用,使用不当会影响性能
建议将所有迭代器数据处理模式处理集合的代码都转换为Stream API的方法,因为Stream API能更清晰地表达数据处理管道的意图,通过短路和延迟载入以及利用现代计算机的多核架构,我们可以对Stream进行优化
??重构现有代码的建议
使用 default (默认方法)重新定义接口 ===================》
Java 8中接口方法可以包含实现类,类可以从多个接口中继承它们的默认方法(默认方法包含实现),充分利用这些功能为我们服务,保持接口的精致性和正交性,能帮助我们在现有的代码基础上最大程序的实现代码复用和行为模式
??灵活利用 Java 8 接口的默认方法,可以实现多继承,最大程序的复用代码
如果一个类使用相同的函数签名从多个地方(比如另一个类或接口)继承了方法,通过三条规则可以进行判断
1.类中的方法优先级最高,类或父类中声明的方法的优先级高于任何声明为默认方法的优先级
2.如果无法依据第一条进行判断,那么子接口的优先级更高,函数签名相同时,优先选择拥有最具体实现的默认方法的接口,即如果B继承了A,那么B就比A更加具体
3.最后如果还是无法判断,继承了多个接口的类必须通过显示覆盖的调用期望的方法
??虽然这种冲突可能极少的发生,但是一单发生这样的状况,必须要有一套规则来确定
使用 optional 取代 null ===================》
ull 带来的种种问题:
1.它是错误之源 -- NullPoninterException 是目前Java程序开发中最典型的异常
2.它使你的代码彭章 -- 它让你的代码充斥着深度嵌套的null检查,代码可读性糟糕透顶
3.它自身毫无意义 -- null自身没有任何语义,尤其是,它代表的是静态类型语言中以一种错误的方式对缺失变量值的建模
4.它破坏Java哲学 -- Java 一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针
5.导致大量问题 -- null并不属于任何类型,这意味着它可以被复制给人以引用类型的变量
??万恶之源 ----- null
通过类型系统让你的域模型中隐藏的知识显式地体现在你的代码中,换句话说,你永远不应该忘记语言的首要功能就是沟通,即使对程序设计语言而言也没什么不同声明方法接受一个 optional 参数,或者将结果作为 optional 类型返回,让你的同事或者未来你方法的使用者,很清楚的知道它是可以接受空值,或者可能返回一个空值
?? opational 如果只是声明空值,设置默认值,那么出现空值该如何处理??
使用Optional从文件中读取属性:
??
ublic int readDuration(Properties properties, String name){
// 1.0 不用Optional 封装类的写法
// String value = properties.getProperty(name);
// if(value != null){
// try{
// int i = Integer.parseInt(value);
// if(i 0){
// return i;
// }
// }catch (NumberFormatException e){
//
// }
// return 0;
// }
// optional 封装类
return Optional
.ofNullable(properties.getProperty(name)) //获取 property 然后将结果封装到 optional , optional 使用ofNullable创建
.flatMap(OptionalUtility :: stringToInt) //Lambda 将 string 转为 Integer ,
.filter(i - i 0) //过滤 value 0
.orElse(0); //如果为null, 就返回0
}
Java 8 之前的Date和Calendar类的缺陷和糟糕的设计,导致用户转投第三方时间库,比如joda-time,所以在Java 8提供了高质量的时间和日期支持,在java.time包中整合了很多 Joda-time 的特性,常用的包邮LocalDate、LocalTime、Instant、Duration、Period
?? 改进历史问题
LocalDate类是一个不可变对象,它只提供简单的日子,并不包含当天的时间信息,也不附带任何和时区相关的信息。
??Java 8 中简单的日期类
LocalTime用来表示当天时间的对象,并不包含日期信息,也不附带任何和时区相关的信息
??Java 8 中简单的时间类
LocalDateTime 合并时间和日期,它是 LocalDate和LocalTime的合体,它同时表示日期和时间,但不带有市区信息
??Java 8 中简单的时间和日期对象的合体类
TemporalAdjuster提供了大量对于常见的用力,日期和时间的API,例如将日期调整到下周日,下个工作日,或者本月的最后一天
?主要用于修改时间
DateTimeFormatter 用于解析日期时间对象,打印已急输出,对于老的java.util.DateFormat相比较,所有的DateTimeFormatter实例都是线程安全的
??获取本地时间字符串可以写成:
LocalDateTime.now().format(DateTimeFormatter.ofPattern( yyyy-MM-dd hh:mm:ss ))
感觉Java 8所有的特性,都变成了链式变成,或者说是函数式编程
Java 8新增的java.time.ZoneId类是老版java.util.TimeZone的替代品,新版的日期和时间API的时区的处理被极大的简化了,它的设计目标就是要让你无需为时区处理的复杂和繁琐而操心,跟其他日期和时间类一样,ZoneId类也是无法修改的
??记录就好,时区这章太无聊,看的想睡觉