20145307第七周JAVA学习报告
20145307《Java程序设计》第七周学习总结
教材学习内容总结
Lambda
Lambda语法概述: Arrays的sort()方法可以用来排序,在使用sort()时,需要操作java.util.Comparator来进行说明,这样一来,语法就显得有些冗长。在JDK8中,可以使用Lambda语法改变Arrays.sort()的可读性: Comparator byLength =(String name1,String name2)->name1.length() - name2.length();
编译器可以从byLength变量的声明类型,推断name1与name2的类型,因此可以再简化为:Comparator byLength = (name1,name2)->name1.length() - name2.length();方法参考的特性,在重用现有API上扮演了重要角色。重用现有方法实作,可避免到处写下Lambda运算式,方法参考不仅避免了重复撰写Lambda表达式,也可以让程序代码更清楚.
Lambda表达式与函数接口:等号右边是Lambda表示式(Expression),等号左边是作为Lambda表示式的目标型态(Target type)Comparator byLength = (String name1,String name2)->name1.length() - name2.length();
如果有目标型态的话,在编译器可推断出类型的情况下,就可以不写出Lambda表示式的参数型态
Lambda表示式本身是中性的,不代表任何型态的实例,同样的Lambda表示式,可用来表示不同目标型态的对象操作
JDK8的Lambda并没有导入新类型来作为Lambda表达式的类型,而是就现有的interface语法来定义函数接口,作为Lambda表达式的目标类型。
如果接口使用了@FunctionalInterface来标注,而本身并非函数接口的话,就会引发编译错误。
Lambda遇上this与final:Lambda表示式并不是匿名类别的语法蜜糖,如果Lambda表示式中捕获的局部变量本身等效于final局部变量,可以不用在局部变量上加上final,JDK8特意禁止在Lambda中修改局部变量的值。 方法与构造函数参考:方法参考(Method references)可以避免你到处写下Lambda表示式,尽量运用现有的API实作,也可以改善可读性。
接口默认方法:在JDK8中,interface定义时可以加入默认操作,或者称为默认方法(Default methods),forEach()方法本身已有操作,所以不会破坏Iterable现有的其他操作。在默认方法中不能使用数据成员,因为接口本身不能定义数据成员,也就是默认方法中不能用直接变更状态的流程。
Functional与Stream API 使用Optional取代null:null的最根本问题在于语义含糊不清,调用方法时如果返回类型是Optional,应该立即想到它可能包含也可能不包含值,在Optional没有包含值的情况下,get会抛出NoSuchElementException,Optional的ofNullable()来衔接程式库中会传回null的方法。 标准API的函数接口:基本上可以分为Consumer、Function、Predicate与Supplier四个类型
如果需要的行为是接受一个自变量,然后处理后不传回值,就可以使用Consumer接口,接受了自变量但没有传回值,这行为就像纯綷消耗了自变量,就是命名为Consumer的原因。如果真的有结果产生,就是以副作用(Side effect)形式呈现,例如:
Arrays.asList("Justin","Monica","Irene").forEach(out::println);
接受一个自变量,然后以该自变量进行计算后传回结果,就可以使用Function接口,行为就像是数学函数y=f(x),给予x值计算出y值的概念,因此命名为Function。
接受一个自变量,然后只传回boolean值,也就是根据传入的自变量直接论断真假的行为,就可以使用Predicate函数接口。 需要的行为是不接受任何自变量,然后传回值,那可以使用Supplier函数接口。
使用Stream进行管道操作:绝大多数的Stream并不需要呼叫close()方法,JDK8中要close()的是Files.lines()、Files.list()与Files.walk()方法。
JDK8引入了Stream API,也引入了管道操作风格,一个管道基本上包括了几个部分:来源、零或多个中间操作、一个最终操作。
时间与日期
时间的度量:
就目前来说,即使标注为格林威治标准时间(GMT时间),实际上谈到时间指的是UTC时间。 秒的单位定义是基于TAI,也就是铯原子辐射振动次数。 UTC考虑了地球自转越来越慢而有闰秒修正,确保UTC与UT相差不会超过0.9秒。 Unix时间是1970年1月1日00:00:00 为起点而经过的秒数,不考虑闰秒。
年历简介:
儒略历:修正了罗马历隔三年设置一闰年的错误,改采四年一闰。 格里高利历:改革了儒略历。 ISO 8601标准:并非年历系统,而是时间日期表示方法的标准,用以统一时间日期的数据交换格式。
认识时区:牵涉到地理、法律、经济、社会甚至政治等问题
UTC偏移(offset)。 有些国家的领土横跨的经度很大,一个国家有多个时间反而造成困扰,因而不採取每15度偏移一小时的作法。
实施日光节约时间(Daylight saving time)。 认识Date与Calender
时间轴上瞬间的Date:
如果想要取得系统时间,方法之一是使用System.currentTimeMillis()方法,返回的是long类型整数,代表1970年1月1日0时0分0秒0毫秒至今经过的毫秒数,有人会使用Date实例来取得系统时间描述,不过Date也是偏向机器的时间观点
Date有两个构造函数可以使用,一个可使用epoch毫秒数构建,另一个为无自变量构造函数,内部亦是使用System.currentTimeMillis()取得毫秒数,调用getTime()可取得内部保存的epoch毫秒数值。 不建议使用toString()来得知年月日等栏位资讯,有关于字串时间格式的处理,不再是Date的职责。
格式化时间日期的DateFormat:
字串时间格式的处理,职责落到了java.text.DateFormat身上,其操作类别java.text.SimpleDateFormat,可以直接建构SimpleDateFormat实例,或使用DateFormat的getDateInstance()、getTimeInstance()、getDateTimeInstance()等静态方法。 直接构建SimpleDateFormat的好处是,可使用模式字符串自定义格式。
处理时间日期的Calendar:
想要取得某个时间日期资讯,或者是对时间日期进行操作,可以使用Calendar实例,通过Calendar的getInstance()取得的Calendar实例,默认就是取得GregorianCalendar实例,例如:
Calendar calendar = Calendar.getInstance();
取得Calendar实例后,可以使用getTime()取得Date实例,如果想要取得年月日等日期时间字段,可以使用get()方法指定Calender上的字段枚举常数:
out.println(calendar.get(Calendar.YEAR)); out.println(calendar.get(Calendar.MOUNTH)); out.println(calendar.get(Calendar.DATE));
如果要设定时间日期等字段,不要对Date设定,应该使用Calendar,同样地,月份的部分使用枚举常数设定:
Calendar calendar = Calendar.getInstace(); calendar.set(2016,Calendar.JAN,2); //2016/1/2 out.println(calendar.get(Calendar.YEAR)); //2016 out.println(calendar.get(Calendar.MOUNTH)); //Calendar.JAN为1 out.println(calendar.get(Calendar.DATE)); //2
在取得一个Calendar的实例后,可以使用add()方法,来改变Calendar的时间:
calendar.add(Calendar.MONTH,1); //Calendar时间加一个月 calendar.add(Calendar.HOUR,3); //Calendar时间加三小时 calendar.add(Calendar.YEAR,-2); //Calendar时间减两年 calendar.add(Calendar.DATE,3); //Calendar时间加三天
如果打算只针对日期中某个字段加减,则可以使用roll()方法:
calendar.roll(Calendar.DATE,1); //只对日字段加1
设定TimeZone:
使用java.util.TimeZone的getDefault()来取得默认时区信息。
想要取得指定时区的TimeZone实例,可以使用ID字串,例如:
TimeZone taipeiTz = TimeZone.getTimeZone("Asia/Taipei");
JDK8新时间日期API
机器时间观点的API:
Date名称看来像是人类的时间概念,实际却是机器的时间概念,混淆机器与人类时间观点会引发的问题之一像是日光节约时间。 不该使用Date实例的toString()来得知人类观点的时间信息,Date实例应该只代表机器观点的时间资讯,真正可靠的资讯只有内含的epoch毫秒数。
人类时间观点的API:
对于片段的日期时间,JDK8新时间与日期API有LocalDateTime()、LocalDate()、LocalTime()等类来定义,这些类基于ISO 8601年历系统,是不具时区的时间与日期定义。 在新的时间与日期API中,UTC偏移量与时区的概念是分开的,offsetDateTime单纯代表UTC偏移量,使用ISO 8601。如果只想表示2014年,可以使用Year,如果想表示2014/5,可以使用YearMonth,如果只想表示5月,可以使用Month,如果想表示5/4,可以使用MonthDay,其中Month是enum型,如果你想要取得代表月份的数字,不要使用oridinal()方法,因为oridinal()是enum在定义时的顺序,从0开始,想要取得代表月份的数要通过getValue()方法。
对时间的运算:period与Duration乍看有些难区别,period是日期差,between()方法只接受LocalDate,不表示比“日”更小的单位。然而Duration是时间差,between()方法可以接受LocalDateTime()、LocalDate()、LocalTime(),不表示比“天”更大的单位。