Openjdk是jdk的开放源代码版本
二者授权协议不同
OpenJDK不包含部署功能 (javaweb start /控制面板)
OpenJDK源码不完整,部分代码使用开源代码替换
多个jdk切换实现
source /etc/profile
切换命令: jdk11
或 jdk12
JDK 5
可变参数,泛型
① 可变参数本质就是一个数组,arr就是一个数组的引用地址(反编译工具查看源代码)
②一个方法 可以有可变参数和普通参数,但是可变参数必须放到参数列表末尾;
③ 一个方法 有且只能有一个可变参数;
public class Main {
public static void main(String[] args) {
String[] a = raaaaa("a","v","a");
System.out.println(a.length);
}
private static <T> T[] raaaaa(T... values){
for (T value : values) {
// sout
}
return values;
}
}
foreach
JDK 7
try multi catch
@Override
AutoCloseable
JDK 8
https://www.shiyanlou.com/courses/539/learning/?id=1832
面对大型数据集合,java还欠缺高效的并行操作 —-> Lambda表达式
面向对象编程是对数据进行抽象,函数式编程是对行为进行抽象
一、Lambda表达式 ☆☆☆☆☆
设计匿名内部类时,是为了将代码作为数据传递,不过匿名内部类不够简便
在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
Lamda优缺点
优点:1. 简洁。2. 非常容易并行计算。3. 可能代表未来的编程趋势。
缺点:1. 若不用并行计算,很多时候计算速度没有比传统的 for 循环快。(并行计算有时需要预热才显示出效率优势)2. 不容易调试。3. 不易读
例1 旧版本如何对StringList排序
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
//传入一个List对象以及一个匿名的比较器对象 给sort方法
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
修改为lambda表达式
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
再优化(对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字)
Collections.sort(names, (String a, String b) -> b.compareTo(a));
再优化(Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。)
Collections.sort(names, (a, b) -> b.compareTo(a));
例2 遍历赋值
外部迭代的方式,也就是for或者while循环。
List persons = asList(new Person("Joe"), new Person("Jim"), new Person("John"));
for (Person p : persons) {
p.setLastName("Doe");
}
lambda表达式
persons.forEach(p->p.setLastName("Doe"));
例3 Map 的 merge 方法
- merge() 可以这么理解:它将新的值赋值到 key (如果不存在)或更新给定的key 值对应的
- 该方法接收三个参数,一个 key 值,一个 value,一个 remappingFunction ,如果给定的key不存在,它就变成了 put(key, value) 。但是,如果 key 已经存在一些值,我们 remappingFunction 可以选择合并的方式,然后将合并得到的 newValue 赋值给原先的 key。
```java
Map
studentScoreMap2 = new HashMap<>(); studentScoreList.forEach(studentScore -> studentScoreMap2.merge( studentScore.getStuName(), studentScore.getScore(), Integer::sum) );
System.out.println(objectMapper.writeValueAsString(studentScoreMap2));
// 结果如下: // {“李四”:228,”张三”:215,”王五”:235}
<a name="4a97f032"></a>
### Lambda表达式的几个最重要的特征:
- 可选的类型声明:你不用去声明参数的类型。编译器可以从参数的值来推断它是什么类型。
- 可选的参数周围的括号:你可以不用在括号内声明单个参数。但是对于很多参数的情况,括号是必需的。
- 可选的大括号:如果表达式体里面只有一个语句,那么你不必用大括号括起来。
- 可选的返回关键字:如果表达式体只有单个表达式用于值的返回,那么编译器会自动完成这一步。若要指示表达式来返回某个值,则需要使用大括号。
<a name="8778a43d"></a>
## 二、流Stream ☆☆☆
Stream作为java8的新特性,基于lambda表达式,是对集合对象功能的增强,它专注于**对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作**<br />**Stream的原理:**将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
- stream() − 为集合创建串行流
- parallelStream() - 为集合创建并行流
- 中间操作主要有以下方法(此类型方法返回的都是Stream):map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
- 终止操作主要有以下方法:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
**分组**
```java
//List 以ID分组 Map<Integer,List<Apple>>
Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
System.err.println("groupBy:"+groupBy);
{1=[Apple{id=1, name='苹果1', money=3.25, num=10}, Apple{id=1, name='苹果2', money=1.35, num=20}], 2=[Apple{id=2, name='香蕉', money=2.89, num=30}], 3=[Apple{id=3, name='荔枝', money=9.99, num=40}]}
map(转换)
List<String> addresses = students
.stream()
.map(s ->"--"+s.getAddress())
.collect(Collectors.toList());
/**
* List -> Map
* 需要注意的是:
* toMap 如果集合对象有重复的key,会报错Duplicate key ....
* apple1,apple12的id都为1。
* 可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
*/
Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
distinct(去重) 重写了equals和hashCode()方法
List<String> addresses = students
.stream()
.map(s ->"--"+s.getAddress())
.distinct()
.collect(Collectors.toList());
filter
Stream<Person> personStream = collection.stream().filter(new Predicate<Person>() {
@Override
public boolean test(Person person) {
return "男".equals(person.getGender());//只保留男性
}
});
Stream<Person> personStream = collection.stream()
//只保留男性
.filter(person -> "男".equals(person.getGender()));
去重后遍历
students
.stream()
.map(s -> "--" + s.getAddress())
.distinct()
.forEach(addr->{
System.out.println(addr+"--");
});
sorted(排序)
students
.stream()
.map(Student::getAge)
.distinct()
.sorted()
.forEach(age->{
System.out.println(age+"--");
});
limit(限制返回个数)
集合limit,返回前几个元素
skip(删除元素)
集合skip,删除前n个元素
reduce(聚合)
List<String> list = Arrays.asList("欢","迎","你");
String appendStr = list.stream().reduce("北京",(a,b) -> a+b);
System.out.println(appendStr);
求和
//计算 总金额
BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
System.err.println("totalMoney:"+totalMoney);
min 找最小
Optional<Student> s = students
.stream()
.distinct()
.min((o1, o2) -> {
if (o1.getAge() > o2.getAge()) {
return 1;
} else {
return -1;
}
});
System.out.println(s.get().id);
三、Optional ☆☆
public final class Optional<T> extends Object
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
四、默认方法(Default Methods) ☆☆
在 java 8 之前,接口与其实现类之间的 耦合度 太高了(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。这在 lambda 表达式作为 java 8 语言的重要特性而出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。
五、时间
由于 SimpleDateFormat 是线程不安全的(一般使用 SimpleDateFormat 的时会把它定义成静态变量,从而避免频繁地创建它的对象实例,但 SimpleDateFormat 内部使用 Calendar 去完成日期的转换,多线程情况下可能会出现线程不安全情况)
相互转化: https://www.cnblogs.com/zszxz/p/12255663.html
可以使用Instant代替Date
// 加8小时,北京时间
Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println("秒数:"+now.getEpochSecond());
System.out.println("毫秒数:"+now.toEpochMilli());
LocalDateTime代替Calendar
//获取秒数 (东8区,也就是北京时间)
Long second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
//获取毫秒数(东8区,也就是北京时间)
Long milliSecond = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 输出当前时间:2019-04-24T19:41:21.858
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
// 当前时间增加20分钟
LocalDateTime afterPlusTime = LocalDateTime.now().plus(20, ChronoUnit.MINUTES);
System.out.println(afterPlusTime);
// 二者转化
Long timestamp = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
LocalDateTime time2 =LocalDateTime.ofEpochSecond(timestamp/1000,0,ZoneOffset.ofHours(8));
// 比较大小
//你的时间在当前时间之前是true
System.out.println(localDateTime.isBefore(LocalDateTime.now()));
//在当前时间之后是
System.out.println(localDateTime.isAfter(LocalDateTime.now()));
// 加减时间 2019-01-31
LocalDate localDate = LocalDate.now();
//计算去年 2018-01-31
LocalDate previousYear = localDate.minus( 1, ChronoUnit.YEARS );
//减30天 2019-01-01
LocalDate previousDay = localDate.minus( 30, ChronoUnit.DAYS );
// jia 坑!: 需要赋值
startLocalDateTime = startLocalDateTime.plus( 1, ChronoUnit.MONTHS);
LocalDate localDate = LocalDate.now();//当前日期
int week = localDate.getDayOfWeek().getValue(); //计算今天是星期几
LocalDate endTime = localDate.minusDays( week ); //计算上周日的日期
DateTimeFormatter代替SimpleDateFormat
LocalDateTime time = LocalDateTime.now();
String timeStr = time.format(DateTimeFormatter.ofPattern("yyyy年年MM月dd日 HH:mm:ss"));
System.out.println(timeStr);
JDK9
模块化
JDK10
var
JDK11
重要:
- JEP181基于嵌套的访问控制 Nest
嵌套类可以访问其他类的私有成员(1.源码级访问2.反射)
- JEP309 动态类文件常量
- JEP321 标准HTTP客户端 java.net.http包
同步发送get
异步发送get
不重要
JDK12
20190319
重要
1.增强的switch语句
不重要
JDK 14
改进的switch表达式
第一次出现在Java 12和13中,在Java 14中获得了完全的支持
新的switch表达式的优点是,不再有缺省跳过行为(fall-through),更全面,而且表达式和组合形式更容易编写,因此出现bug的可能性就更低。例如,switch表达式现在可以使用箭头语法,如下所示:
文本块
- instanceof支持模式匹配(语言特性)
- NullPointerException(JVM特性)