JDK1.8改动
在jdk1.8中对hashMap等map集合的数据结构优化。hashMap数据结构的优化
原来的hashMap采用的数据结构是哈希表(数组+链表),hashMap默认大小是16,一个0-15索引的数组,如何往里面存储元素,首先调用元素的hashcode
方法,计算出哈希码值,经过哈希算法算成数组的索引值,如果对应的索引处没有元素,直接存放,如果有对象在,那么比较它们的equals方法比较内容
如果内容一样,后一个value会将前一个value的值覆盖,如果不一样,在1.7的时候,后加的放在前面,形成一个链表,形成了碰撞,在某些情况下如果链表
无限下去,那么效率极低,碰撞是避免不了的
加载因子:0.75,数组扩容,达到总容量的75%,就进行扩容,但是无法避免碰撞的情况发生
在1.8之后,在数组+链表+红黑树来实现hashmap,当碰撞的元素个数大于8时 & 总容量大于64,会有红黑树的引入
除了添加之后,效率都比链表高,1.8之后链表新进元素加到末尾
ConcurrentHashMap (锁分段机制),concurrentLevel,jdk1.8采用CAS算法(无锁算法,不再使用锁分段),数组+链表中也引入了红黑树的使用
lambda表达式
lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码,最直观的优点事可以简洁代码
lambda表达式的语法格式如下:
(参数类型 参数名) -> {
方法体;
return 返回值;
}
示例
List<Phone> list = new ArrayList<Phone>();
Phone p1 = new Phone(3999.0, "小米");
Phone p2 = new Phone(4999.0, "华为");
list.add(p1);
list.add(p2);
/**
* 无返回值
*/
list.stream().filter(phone -> phone.getPrice()>4000).limit(3).forEach(System.out::println);
Stream<Phone> stream = list.stream();
stream.filter(phone -> phone.getPrice()>4000);
System.out.println(stream.toString());
list.stream().filter(p->p.getType().equals("小米")).forEach(System.out::println);
Lambda 表达式的省略规则:
- 小括号中的参数类型可以省略。
- 如果小括号中只有一个参数,那么可以省略小括号。
- 如果大括号中只有一条语句,那么可以省略大括号,return,分号。
函数式接口
- 如果一个接口只有一个抽象方法就为函数式接口
- 某个接口只有一个抽象方法,但我们并没有给该接口声明 @FunctionalInterface 注解,那么编译器依旧会将该接口看作是函数式接口
- 重写 Object 类里的方法不会导致函数式接口失效
- jdk1.8 以后接口里面可以定义方法的实现,这种方法叫做 default-method
public interface Mytest<T> {
boolean test(T t);
default double add(double a,double b){
return a+b;
};
}
- 功能性接口 function 接受参数 有返回值
Function<String,String> function = str->str+"收参返果";
String s = function.apply("function");
System.out.println(s);
- 断言性接口 predicate 接受参数 返回true false
Predicate<String> predicate = "ab,c".split(",")[0]::equals;
Boolean s = predicate.test("ac");
System.out.println(s);
- 供给性接口 supplier 不接受参数 有返回值
Supplier supplier = "Hello"::toLowerCase;
System.out.println(supplier);
- 消费性接口 consumer 接受参数 没有返回值
Consumer<String> consumer = System.out::println;
consumer.accept("输出");
方法引用和数组引用
方法引用
- lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
- 若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method
BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);
BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;
Integer result = biFun2.apply(100, 200);
System.out.println(result);
// 方法引用-类名::实例方法名
BiFunction<String, Integer, Character> fun1 = (str1, str2) -> str1.charAt(str2);
BiFunction<String, Integer, Character> fun2 = String::charAt;
Character result2 = fun2.apply("hello", 0);
Character result1 = fun1.apply("hello", 0);
System.out.println(result1);
数组引用
Function<Integer, String[]> fun = (x) -> new String[x];
Function<Integer, String[]> fun2 = String[]::new;
String[] strArray = fun2.apply(10);
Arrays.stream(strArray).forEach(System.out::println);
Stream API
Stream操作的三个步骤
- 创建stream
- 中间操作(过滤、map)
- 终止操作
创建stream
// 1,校验通过Collection 系列集合提供的stream()或者paralleStream()
List<String> list = new ArrayList<>();
Strean<String> stream1 = list.stream();
// 2.通过Arrays的静态方法stream()获取数组流
String[] str = new String[10];
Stream<String> stream2 = Arrays.stream(str);
// 3.通过Stream类中的静态方法of
Stream<String> stream3 = Stream.of("aa","bb","cc");
// 4.创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);
//生成
Stream.generate(() ->Math.random());
中间操作
/**
* 筛选 过滤 去重
*/
emps.stream()
.filter(e -> e.getAge() > 10)
.limit(4)
.skip(4)
// 需要流中的元素重写hashCode和equals方法
.distinct()
.forEach(System.out::println);
/**
* 生成新的流 通过map映射
*/
emps.stream()
.map((e) -> e.getAge())
.forEach(System.out::println);
/**
* 自然排序 定制排序
*/
emps.stream()
.sorted((e1 ,e2) -> {
if (e1.getAge().equals(e2.getAge())){
return e1.getName().compareTo(e2.getName());
} else{
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
终止操作
/**
* 查找和匹配
* allMatch-检查是否匹配所有元素
* anyMatch-检查是否至少匹配一个元素
* noneMatch-检查是否没有匹配所有元素
* findFirst-返回第一个元素
* findAny-返回当前流中的任意元素
* count-返回流中元素的总个数
* max-返回流中最大值
* min-返回流中最小值
*/
/**
* 检查是否匹配元素
*/
boolean b1 = emps.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
boolean b2 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b2);
boolean b3 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b3);
Optional<Employee> opt = emps.stream()
.findFirst();
System.out.println(opt.get());
// 并行流
Optional<Employee> opt2 = emps.parallelStream()
.findAny();
System.out.println(opt2.get());
long count = emps.stream()
.count();
System.out.println(count);
Optional<Employee> max = emps.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(max.get());
Optional<Employee> min = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min.get());
reduce(操作数据)和collect(收集流)
/**
* reduce :规约操作
*/
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer count2 = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(count2);
Optional<Double> sum = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(sum);
/**
* collect:收集操作
*/
List<Integer> ageList = emps.stream()
.map(Employee::getAge)
.collect(Collectors.toList());
ageList.stream().forEach(System.out::println);
Optional容器
使用Optional容器可以快速的定位NPE,并且在一定程度上可以减少对参数非空检验的代码量。
/**
* Optional.of(T t); // 创建一个Optional实例
* Optional.empty(); // 创建一个空的Optional实例
* Optional.ofNullable(T t); // 若T不为null,创建一个Optional实例,否则创建一个空实例
* isPresent(); // 判断是够包含值
* orElse(T t); //如果调用对象包含值,返回该值,否则返回T
* orElseGet(Supplier s); // 如果调用对象包含值,返回该值,否则返回s中获取的值
* map(Function f): // 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();
* flatMap(Function mapper);// 与map类似。返回值是Optional
*
* 总结:Optional.of(null) 会直接报NPE
*/
Optional<Employee> op = Optional.of(new Employee("zhansan", 11, 12.32, Employee.Status.BUSY));
System.out.println(op.get());
// NPE
Optional<Employee> op2 = Optional.of(null);
System.out.println(op2);
@Test
public void test2(){
Optional<Object> op = Optional.empty();
System.out.println(op);
// No value present
System.out.println(op.get());
}
@Test
public void test3(){
Optional<Employee> op = Optional.ofNullable(new Employee("lisi", 33, 131.42, Employee.Status.FREE));
System.out.println(op.get());
Optional<Object> op2 = Optional.ofNullable(null);
System.out.println(op2);
// System.out.println(op2.get());
}
@Test
public void test5(){
Optional<Employee> op1 = Optional.ofNullable(new Employee("张三", 11, 11.33, Employee.Status.VOCATION));
System.out.println(op1.orElse(new Employee()));
System.out.println(op1.orElse(null));
}
@Test
public void test6(){
Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
op1 = Optional.empty();
Employee employee = op1.orElseGet(() -> new Employee());
System.out.println(employee);
}
@Test
public void test7(){
Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));
System.out.println(op1.map( (e) -> e.getSalary()).get());
}
新时间日期API
LocalDate LocalDateTime 简单应用(线程安全)
LocalDate today = LocalDate.now();
LocalDate oldDate = LocalDate.of(1996,10,01);
LocalDate strToDate = LocalDate.parse("1999-04-04");
System.out.println(today);
System.out.println(oldDate);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(localDateTime));
以上为jdk1.8新特性简单应用,有兴趣可以看看源码,英文可以借助Translation组件翻译还不错。