1. default 关键字
java里,接口是不能有方法的实现的。1.8 通过 default 关键字可以实现
public interface NewChar {
public void test1();
public default void test2(){
System.out.println("我是新特性1");
}
}
作用是什么?
定义一个默认方法,这个接口的实现类实现了这个接口之后,不用管这个方法的实现,可以直接调用。
2. lambda 表达式
意味着开始使用函数式编程
函数式编程:
- 是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量。
- 也就是说,输入确定,输出也就是确定的。
特点
- 允许把函数本身作为参数传入另一个函数,还允许返回一个函数
格式
- ->符号
- 左侧 参数列表
- 右侧 所需的功能,即lambda体
先来看一个例子
//常规的 集合排序 需要对接口方法重写
public void test1(){
List<String> list =Arrays.asList("aaa","fsa","ser","eere");
//对接口方法重写
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
for (String string : list) {
System.out.println(string);
}
}
//不带参数类型的lambda写法
public void testLamda2(){
List<String> list =Arrays.asList("aaa","fsa","ser","eere");
// ->符号
Collections.sort(list, (a,b)->b.compareTo(a)
);
for (String string : list) {
System.out.println(string);
}
3. 函数式接口
仅仅只包含一个抽象方法的接口,每一个该类型的 lambda 表达式都会匹配到这个抽象方法
// 这个注解定义函数式接口
@FunctionalInterface
public interface MyLamda {
//只允许定义一个抽象方法
public void test1(String y);
//这里如果继续加一个抽象方法便会报错
// public void test1();
//default方法可以任意定义
default String test2(){
return "123";
}
default String test3(){
return "123";
}
//static方法也可以定义
static void test4(){
System.out.println("234");
}
}
看一下调用抽象方法
MyLamda m = y -> System.out.println("ss"+y);
4. 方法和构造函数引用
符号 :: ClassName::MethodName 没有()
- 符号前面 目标引用
- 符号后面 方法名称
先定义一个函数式接口
@FunctionalInterface
public interface TestConverT<T, F> {
F convert(T t);
}
测试
public void test(){
//调用Integer的valueOf方法
TestConverT<String, Integer> t = Integer::valueOf;
Integer i = t.convert("111");
System.out.println(i);
}
对于构造方法也可以这样调用
//实体类User和它的构造方法
public class User {
private String name;
private String sex;
public User(String name, String sex) {
super();
this.name = name;
this.sex = sex;
}
}
//User工厂
public interface UserFactory {
User get(String name, String sex);
}
//测试类 这里编译器会根据uf调用的参数来选择合适的构造函数
UserFactory uf = User::new;
User u = uf.get("ww", "man");
5. 局部变量限制
- Lambda可以没有限制的捕获实例变量和静态变量。
- 但是局部变量必须声明为 final
- 使用lambda的线程,可能会在分配该变量的线程将这个变量回收之后,去访问的。
- 因此,在访问局部变量时,实际上是访问他的副本,而不是原始变量。
- 如果被final修饰之后,那就没什么区别了(原始和副本)
final int num = 1;
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2);
6. Date api更新
7. Stream
定义:
- 不是集合元素,不是数据结构,不保存数据
- 更新一个高级版的Iterator,用户只需要给出对其包含的元素执行什么操作,stream会在内部进行遍历,做出相应的数据转换。
- 可以并行化操作,遍历时,数据会被分成多个段,每一个段都在不同的线程中处理,然后将结果一起输出。
类型有两种:
- Intermediate
- 打开流,做出某种数据映射或过滤,然后返回一个新的流。
- 一个流后可以跟0个或者多个这种流
- Terminal
- 会真正的开始流的遍历,并生成一个结果 或副作用(side effect)
- 所以一个流只能有一个terminal操作,执行完,流就被用光了。
int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight())
.sum();
- stream() 获取当前widgets的source
- filter mapTotInt 为Intermediate操作,进行数据筛选和转换
- sum为terminal操作,得到一个求和的结果
所以流的使用就是实现一个 filter-map-reduce过程,产生一个结果或者导致一个副作用(side effect)
构造流的方式
// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();
流的操作 参考
- Intermediate
- map (mapToInt, flatMap 等)(映射)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
- Terminal
- forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
- Short-circuiting
- anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 limit
8. Annotation注解
Java 8允许我们把同一个类型的注解使用多次,只需要给该注解标注一下@Repeatable即可。
注解拓展,注解几乎可以使用在任何元素上:局部变量、接口类型、超类和接口实现类。
9. Optional
解决空指针的问题
提供了一些方法,来做判断
//不管param是不是null 都不会抛出异常
Optional<String> nullOptional = Optional.ofNullable(param);
10. 新的工具和引擎
Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
11. HashMap 和 ConcurrerentHashMap 优化
- 链表树化
- 头插法改成尾插法
- ConcurrerentHashMap 改为 Node 数组 + cas + synchronized
12. synchronized 优化,锁膨胀
13. JVM 优化
Java 8 中就把方法区的实现移到了本地内存中的元空间中,这样方法区就不受 JVM 的控制了,也就不会进行 GC,也因此提升了性能