【第二十五天】JDK8部分特性:接口可以实体方法、Lambda表达式、函数式接口、Stream、时间包
复习:
1. 反射:剖析一个类,分析这个类的字节码,获取对应的字节码对象以及产生对应的实例对象的过程。
--- 获取字节码对象:
类名.class,对象.getClass(),
Class.forName(类的全路径名);
利用字节码对象获取实例对象
---clz.newInstance(),要求这个类中必须有无参构造;
获取类中对应形式的构造方法对象,
然后利用Constructor对象来产生对应的实例对象。
--- 利用反射实现解耦操作
2. 单元测试:导入Junit测试库,@Test,@Before,@After --- 要求使用的方法没有参数,没有返回值,是非静态的。
3. 注解:本质上是一个接口。利用@interface来定义一个注解。注解中的属性在定义的时候类型只能是基本类型、String、Class、其他注解类型、枚举类型以及这五个类型的一维数组形式。
元注解:@Target,@Retention,@Documented,@Inherited
JDK8的部分特性
接口中的默认方法
从jdk1.8开始,接口中允许定义实体方法。然而这个非静态方法必须用default修饰,而且这个方法必须用public修饰。接口中也允许定义静态方法。
多实现,多继承
interface A {
public default int m(){
return 0;
}
}
interface B {
public default String m(){
return null;
}
}
class C implements A, B {}
C c = new C();
int ? String?c.m();
1 package cn.sgy.day180210; 2 3 public class InterfaceMethodDemo { 4 5 public static void main(String[] args) { 6 7 Calculator c = new Calculator() { 8 9 @Override 10 public int add(int i, int j) { 11 return i+j; 12 } 13 14 }; 15 16 System.out.println(c.max(4, 9)); 17 } 18 } 19 20 interface Calculator{ 21 22 23 public int add (int i, int j); 24 25 public default int max (int i, int j) { 26 return i>j ? i:j; 27 } 28 29 30 public static double sqrt(double d) { 31 return Math.sqrt(d); 32 } 33 }
Lambda表达式
利用指定的表达式形式来重写接口中的抽象方法
(参数列表) -> {方法体}
不产生内部类,任何一个Lambda表达式都不能直接赋值给Object
注意:当利用Lambda表达式来重写方法的时候,要求这个接口中只能有一个抽象方法
函数式接口
Comparator , FileFilter , FilenameFilter
接口中只含有一个抽象方法的接口---函数式接口---@FunctionalInterface(新注解)
Predicate---仲裁者---判断参数是否符合指定的规则
package cn.sgy.day180210; import java.util.function.Predicate; public class PredictDemo { public static void main(String[] args) { Predicate<String> p = str -> str.startsWith("a"); System.out.println(p.test("abc")); System.out.println("kfc".startsWith("a")); } }
Function---转化者---按照指定规则将参数转化为结果类型
package cn.sgy.day180210; import java.util.function.Function; public class FunctionDemo { public static void main(String[] args) { Function<String, Double> f = str -> Math.sqrt(Double.parseDouble(str)); System.out.println(f.apply("2.25")); Function<String, Boolean> f2 = f.andThen(d -> d >10); System.out.println(f2.apply("4.8")); } }
Supplier---供给者---不需要参数,会返回一个值
package cn.sgy.day180210; import java.util.function.Supplier; public class SupplierDemo { public static void main(String[] args) { Supplier<Double> s = Math::random; System.out.println(s.get()); } }
Consumer --- 消费者---需要参数但是没有返回值
package cn.sgy.day180210; import java.util.function.Consumer; public class ConsumerDemo { public static void main(String[] args) { // Consumer<String> c = str -> System.out.println(str); Consumer<String> c = System.out :: println; c.accept("abc"); } }
Stream
不是函数式接口。不是流,而是不存储数据的流式结构。---提供了大量的方法允许对数据进行批量操作:排序,过滤,映射,规约等方法。根据方法的返回值类型分为中间方法(返回值类型依然是Stream)和完结方法(返回值类型是其他类型)。
1 package cn.tedu.stream; 2 3 import java.util.Arrays; 4 import java.util.List; 5 import java.util.Optional; 6 import java.util.stream.Stream; 7 8 public class StreamDemo1 { 9 10 public static void main(String[] args) { 11 12 List<String> list = Arrays.asList("Mike", "Grace", "Jack", "Bob", "John", "Alex", "Selina"); 13 14 // 获取Stream 15 Stream<String> stream = list.stream(); 16 17 // 筛选列表中J开头的名字-> 将所有字母转化为大写 18 // stream.filter(str -> str.startsWith("J")).map(str -> 19 // str.toUpperCase()).forEach(System.out::println); 20 21 // 筛选含有'a'的字符串---获取筛选之后的个数 22 // System.out.println(stream.filter(str -> str.contains("a")).count()); 23 24 // 判断集合中是否含有出现'm'的字符串 25 // System.out.println(stream.filter(str -> str.contains("m")).count() > 26 // 0); 27 // System.out.println(stream.anyMatch(str -> str.contains("a"))); 28 29 // 判断集合中的所有字符串是否都是由字母组成的 30 // System.out.println(stream.filter(str -> 31 // str.matches("[a-zA-Z]+")).count() == list.size()); 32 // System.out.println(stream.allMatch(str -> str.matches("[a-zA-Z]+"))); 33 34 Optional<String> o = stream.reduce((str1, str2) -> str1 + "~" + str2); 35 System.out.println(o); 36 } 37 38 } 39 40 41 42 运行时候一次只能运行一个输出 多个输出会报错
规约---利用指定规则计算元素之间的关系(不是简单的合并还需要去重合)
Optional<String> o = stram.reduce((str1,str2) -> str1 + "~" +str2);
(Optional为了防止产生空集合对象)
时间包
jdk8中对时间体系进行了全新的划分,划分出来一个代表时间的包---java.time
LocalDate---只含有日期而不含有时间
LocalTime---只含有时间而不含有日期
旧的方法 Date
package cn.sgy.day180210; import java.util.Date; public class TimeDemo { public static void main(String[] args) { Date data = new Date(); System.out.println(data); } }
毫秒 --- millis
微秒 --- micros
纳秒 --- nanos
Time包
package cn.tede.time; import java.time.LocalDate; import java.time.temporal.ChronoUnit; //import java.util.Date; public class LocalDateDemo { public static void main(String[] args) { // Date date = new Date(); // System.out.println(date); // 一个只含有日期而不含有时间的类 // 表示获取当前系统的日期 // LocalDate date = LocalDate.now(); // System.out.println(date); // 指定日期 LocalDate date = LocalDate.of(2018, 3, 1); System.out.println(date); System.out.println(date.getDayOfMonth()); System.out.println(date.getDayOfWeek()); System.out.println(date.getDayOfYear()); // 判断是否是一个闰年 System.out.println(date.isLeapYear()); System.out.println(date.plus(5, ChronoUnit.MILLENNIA)); // System.out.println(date.minus(3,ChronoUnit.MILLENNIA)); } }
JVM的运行参数问题
栈内存---计算---每个线程私有一个栈
堆内存---存储对象---被所有线程所共享的
方法区---存储类信息和常量---被所有线程所共享的
本地方法栈---计算---每个线程私有一个本地方法栈
pc计数器---计数和计算线程执行的指令---每个线程所私有的
-Xss:用于限制栈内存的大小的 -Xss128K表示当前线程的栈内存为128K
-Xmn 设置新生代大小
-Xms 设置堆内存的初始内存大小
-Xmx 设置堆内存的最大可用大小
例如: -Xss128k -Xmn5M -Xms10M -Xmx10M表示每个线程的大小是128k,新生代5M,可用堆内存10M,最大可用内存为10M
java -Xmn5M -Xms7M -Xmx10M -XX:+PrintGCDetails Demo
标准参数:-cp
非标准参数:-Xmn -Xss
扩展参数:-XX:+PrintGC -XX:+PrintGCDetails 打印我的回收细节
{解释:GC初代回收(回收新生代,,括号里面是整个内存的大小)第一行结束发现还是放不开,内存变大是因为一些变量又被初始化了,第二次回收以后依然放不开,于是试着往老生代里面放,老生代回收以后还是放不开来这时候就再回收,最后一行就是老生代新生代一起回收,但是还是放不开于是会报错}
eden space 伊甸园区80%---4M
from space和to space 是两块幸存区 各占10%合起来是20%
伊甸园区和幸存区比例是4:1
ParOldGen老生代 7M大小
PSPermGen持久代 Metaspace方法区
GC的回收机制
Mark-sweeping---标记-清理 会出现内存碎片化
Copying---复制---内存耗费会比较大
Mark-compact---标记-整理---比较充分的利用内存,内存耗费小