Java 8(又称为jdk 1.8) 是Java语言开发的一个主要版本。Java 8是oracle公司于2014年3月发布, 可以看成是自Java5以来最具革命性的版本。Java 8为Java语言、编译器、类库、开发工具与JVM带来了大量新特性。
为什么使用Lambda表达式
Lambda是一个匿名函数, 我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格, 使Java的语言表达能力得到了提升。
在Java 8中, Lambda表达式是对象, 而不是函数, 它们必须依附于一类特别的对象类型:函数式接口。
@Test
public void test() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("lalalalalalala");
}
};
r1.run();
Runnable r2=()->System.out.println("lalalalalalala");
r2.run();
}
@Test
public void test() {
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
);
con.accept(t:"lalalalalalal");
Consumer<String> con1 = (String s) ->{
System.out.println(s);
};
con1.accept(t:"lalalalalalalala");
}
数据类型可以省略,因为可由编译器推断得出,称为“类型推断”。
@Test
public void test() {
Consumer<String> con1 = (String s) ->{
System.out.println(s);
};
con1.accept(t:"lalalalalalaala");
Consumer<String> con2 = (s) ->{
System.out.println(s);
};
con2.accept(t:"lalalalalalaaaala");
}
@Test
public void test() {
Consumer<String> con1 = (s) ->{
System.out.println(s);
};
con1.accept(t:"lalalallalala");
Consumer<String> con2 = s->{
System.out. println(s);
};
con2.accept(t:"lalalalalalalalala");
}
@Test
public void test() {
Comparator<Integer> com1 = new Comparator<Integer>() {
@override
public int compare(Integer o1,Integer o2) {
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
}
};
System.out.println(com1.compare(12,21));
Comparator<Integer> com2 = (o1,o2) ->{
System.out.println(o1);
System.out.println(o2);
return o1.compareTo(o2);
};
System.out.println(com2.compare(12,6));
}
@Test
public void test() {
Comparator<Integer> com1 = (o1,o2) ->{
return o1.compareTo(o2);
};
System.out.println(com1.compare(12,6));
Comparator<Integer> com2 = (o1,o2) ->o1.compareTo(o2);
System.out.println(com2.compare(12,21));
}
什么是函数式接口
如何理解函数式接口
Java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer 消费型接口 | T | void | 对类型为T的对象应用操作,包含方法: void accept(T t) |
Supplier 供给型接口 | 无 | T | 返回类型为T的对象, 包含方法:T get() |
Function |
T | R | 对类型为T的对象应用操作, 并返回结果。结果是R类型的对象。 包含方法:R apply(T t) |
Predicate 断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束, 并返回boolean值。包含方法:boolean test(T t) |
对象 ::实例方法名
类 ::静态方法名
类 ::实例方法名
SuppLier中的 T get()
EmpLoyee的空参构造器:EmpLoyee()
@Test
public void test() {
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
System.out.println("*****************");
Supplier<Employee> sup1 = () -> new Employee();
System.out.println(sup1.get());
System.out.println("******************");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。相比较串行的流,并行的流可以很大程度上提高程序的执行效率。Java 8中将并行进行了优化, 我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过parallel() 与sequential() 在并行流与顺序流之间进行切换。
一个数据源(如:集合、数组),获取一个流。
创建Stream方式一:通过集合
Java 8中的Collection接口被扩展, 提供了两个获取流的方法:
default Stream stream() :返回一个顺序流
default Stream parallelStream() :返回一个并行流
@Test public void test() { List<Employee> employees = EmployeeData.getEmpLoyees(); //defauLt Stream
stream() :返回一个顺序流 Stream<Employee> stream = employees.stream(); //default StreamparalLel Stream() :返回一个并行流 Stream<Employee> parallelStream = employees.parallelStream(); }
创建Stream方式二:通过数组
Java 8中的Arrays的静态方法stream() 可以获取数组流:
static Stream stream(T[] array) :返回一个流
重载形式,能够处理对应基本类型的数组:
- public static Int Stream stream(int[] array)
- public static Long Stream stream(long[] array)
- public static Double Stream stream(double[] array)
@Test public void test() { int[] arr=new int[] {1,2,3,4,5,6}; IntStream stream = Arrays.stream(arr); Employee e1 = new Employee (id: 1001, name:"Tom"); Employee e2 = new Employee (id: 1002, name:"Jerry"); Employee[] arr1 = new Employee[]{e1, e2}; Stream<Employee> stream1 = Arrays.stream(arr1); }
创建Stream方式三:通过Stream的of()
可以调用Stream类静态方法of() , 通过显示值创建一个流。它可以接收任意数量的参数。
public static Stream of(T…values) :返回一个流
@Test
public void test() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}
创建Stream方式四:创建无限流
可以使用静态方法Stream.iterate() 和 Stream.generate() ,创建无限流。
迭代
- public static Stream iterate(final T seed,final UnaryOperator f)
生成
- public static Stream generate(Suppliers)
@Test public void test() { //遍历前10个偶数 Stream.iterate(seed:e, t->t+2).1imit(10).forEach(System.out::println); //生成 Stream.generate(Math::random).1imit(10).forEach(System.out::println); }
一个中间操作链,对数据源的数据进行处理。
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
1-筛选与切片
方法 | 描述 |
---|---|
filter(Predicate p) | 接收Lambda, 从流中排除某些元素 |
distinct() | 筛选, 通过流所生成元素的hashCode() 和equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素 不足n个,则返回一个空流。与limit(n) 互补 |
@Test
public void test() {
List<Employee> list = EmployeeData.getEmpLoyees();
Stream<Employee> stream = list.stream();
//filter(Predicate p) 一接收Lambda,从流中排除某些元素。
//练习:查询员工表中薪资大于7000的员工信息
stream.filter(e->e.getSalary() >7000).forEach(System.out::println);
//Limit(n) 一截断流, 使其元素不超过给定数量。
list.stream().1imit(3).forEach(System.out::println);
//skip(n)-跳过元素,返回一个扔掉了前n个元素的。若流中元素不足n个,则返回一个空流。与 Limit(n) 互补
list.stream().skip(3).forEach(System.out::println);
//筛选
list.stream().distinct().forEach(System.out::println);
}
2-映射
方法 | 描述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个 元素上,并将其映射成一个新的元素 |
map ToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个 元素上, 产生一个新的DoubleStream |
map ToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个 元素上, 产生一个新的IntStream |
map ToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个 元素上, 产生一个新的LongStream |
flat Map(Function f) | 接收一个函数作为参数,将流中的每个值都换成另 一个流,然后把所有流连接成一个流 |
@Test
public void test() {
//map(Function f) 一接收一个函数作为参数, 将元素转换成其他形式或提取信息,
//该函数会被应用到每个元素上,并将其映射成一个新的元素
List<String> list = Arrays.asList("aa", "bb","cc", "dd");
list.stream().map(str->str.toUpperCase()).forEach(System.out::println);
//练习:获取员工姓名长度大于3的员工的姓名。
List<Employee> employees = EmployeeData.getEmpLoyees();
Stream<String> namesStream = employees.stream().map(Employee::getName);
namesStream.filter(name->name.length()>3).forEach(System.out::println);
}
3-排序
方法 | 描述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,其中按比较器顺序排序 |
@Test
public void test 4() {
//sorted() 一自然排序
List<Integer> list=Arrays.as List(12, 43, 65, 34, 87, 0, -98, 7);
list.stream().sorted().forEach(System.out::println);
//抛异常, 原因:EmpLoyee没有实现Comparable接口
//List empLoyees = EmpLoyeeData.getEmpLoyees();
//empLoyees.stream().sorted().forEach(System.out::printLn);
//sorted(Comparator com) 一定制排序
List<Employee> employees = EmployeeData.getEmpLoyees();
employees.stream().sorted((e1,e2) ->
int ageValue = Integer.compare(e1.getAge(), e2.getAge());
if(ageValue!=0) {
return ageValue;
} else{
return Double.compare(e1.getSalary(),e2.getSalary());
}
}).forEach(System.out::println);
}
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
1-匹配与查找
方法 | 描述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
find First() | 返回第一个元素 |
find Any() | 返回当前流中的任意元素 |
@Test
public void test() {
List<Employee> employees = EmployeeData.getEmpLoyees();
//aLLMatch(Predicate p) 一检查是否匹配所有元素。
//练习:是否所有的员工的年龄都大于18
boolean allMatch = employees.stream().allMatch(e->e.getAge() >18);
System.out.println(allMatch);
//anyMatch(Predicate p) 一检查是否至少匹配一个元素。
//练习:是否存在员工的工资大于10000
boolean anyMatch = employees.stream().anyMatch(e->e.getSalary() >10000);
System.out.println(anyMatch);
//none Match(Predicate p) 一检查是否没有匹配的元素.
//练习:是否存在员工姓“雷”
boolean noneMatch = employees.stream().noneMatch(e->e.getName().startswith("雷");
System.out.println(noneMatch);
//findFirst一返回第一个元素
Optional<Employee> employee = employees.stream().findFirst();
System.out.println(employee);
//find Any一返回当前流中的任意元素
Optional<Employee> employee1 = employees.parallelStream().findAny();
System.out.println(employee1);
}
方法 | 描述 |
---|---|
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户去做迭代, 称为外部迭代。相反, StreamAPI使用内部迭 代——它帮你把迭代做了) |
@Test
public void test() {
List<Employee> employees = EmployeeData.getEmpLoyees();
//count 返回流中元素的总个数
long count = employees.stream().filter(e->e.getSalary() >5000).count();
System.out.println(count);
//max(Comparator c) 返回流中最大值
//练习:返回最高的工资
Stream<Double> salaryStream = employees.stream().map(e->e.getSalary());
Optional<Double> maxSalary = salaryStream.max(Double::compare);
System.out.println(maxSalary);
//min(Comparator c) 返回流中最小值
//练习:返回最低工资的员工
Optional<Employee> employee = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(),e2.getSalary()));
System.out.println(employee);
//forEach(Consumer c) 内部迭代
employees.stream().forEach(System.out::println) ;
//使用集合的遍历操作
employees.forEach(System.out::println);
}
2-归约
方法 | 描述 |
---|---|
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional |
备注:map和reduce的连接通常称为map-reduce模式, 因Google用它来进行网络搜索而出名。
@Test
public void test() {
//练习1:计算1-10的自然数的和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9,10);
Integer sum = list.stream().reduce(identity:0, Integer::sum);
System.out.println(sum);
//练习2:计算公司所有员工工资的总和
List<Employee> employees = EmployeeData.getEmpLoyees();
Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
//Optional sumMoney = saLaryStream.reduce(DoubLe::sum);
Optional<Double> sumMoney = salaryStream.reduce((d1,d2) ->d1+d2);
System.out.println(sumMoney);
}
3-收集
方法 | 描述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现, 用于 给Stream中元素做汇总的方法 |
Collector接口中方法的实现决定了如何对流执行收集的操作(如收集到List、Set、Map)。
另外,Collectors实用类提供了很多静态方法, 可以方便地创建常见收集器实例,具体方法与实例如下表:
方法 | 返回类型 | 作用 |
---|---|---|
toList | List | 把流中元素收集到List |
toSet | Set | 把流中元素收集到Set |
toCollection | Collection | 把流中元素收集到创建的集合 |
counting | Long | 计算流中元素的个数 |
summingInt | Integer | 对流中元素的整数属性求和 |
averagingInt | Double | 计算流中元素Integer属性的平均值 |
summarizingInt | IntSummaryStatistics | 收集流中Integer属性的统计值。如:平均值 |
@Test
public void test() {
//练习1:查找工资大于6eee的员工, 结果返回为一个List或Set
List<Employee> employees = EmployeeData.getEmpLoyees();
List<Employee> employeeList = employees.stream()
.filter(e->e.getSalary()>6000).collect(Collectors.toList());
employeeList.forEach(System.out::println);
}
其他方法与实例如下表:
方法 | 返回类型 | 作用 |
---|---|---|
joining | String | 连接流中每个字符串 |
maxBy | Optional | 根据比较器选择最大值 |
minBy | Optional | 根据比较器选择最小值 |
reducing | 归约产生的类型 | 从一个作为累加器的初始值开始, 利用BinaryOperator与流中元素逐 个结合,从而归约成单个值 |
collectingAndThen | 转换函数返回的类型 | 包裹另一个收集器,对其结果转转换函数 |
groupingBy | Map |
根据某属性值对流分组,属性为K,结果为V |
partitioningBy | Map |
根据true或false进行分区 |
Optional提供很多有用的方法, 这样我们就不用显式进行空值检测。
创建Optional类对象的方法:
Optional.of(T t) :创建一个Optional实例, t必须非空;
Optional.empty() :创建一个空的Optional实例;
Optional.ofNullable(T t) :t可以为null;
判断Optional容器中是否包含对象:
boolean isPresent() :判断是否包含对象
void ifPresent(Consumer super T> consumer) :如果有值, 就执行Consumer接口的实现代码,并且该值会作为参数传给它
获取Optional容器的对象:
T get() :如果调用对象包含值, 返回该值, 否则抛异常
T orElse(T other) :如果有值则将其返回, 否则返回指定的other对象。
T orElseGet(Supplier extends T> other) :如果有值则将其返回, 否则返回由Supplier接口实现提供的对象。
T orElseThrow(Supplier extends X> exceptionSupplier) :如果有值则将其返回, 否则抛出由Supplier接口实现提供的异常。
@Test
public void test() {
Girl girl = new Girl();
girl = null;
Optional<Girl> optionalGirl = Optional.of(girl);
}
@Test
public void test2() {
Girl girl = new Girl();
girl = null;
optional<Girl> optionalGirl = Optional.ofNulLable(girl)
System.out.println(optionalGirl);
}
@Test
public void test3() {
Girl girl = new Girl();
girl = null;
//of NulLable(Tt) :t可以为null
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
System.out.println(optionalGirl);
Girl girl1 = optionalGirl.orElse(new Girl(name:"zly"));
System.out.println(girl1);
}
public interface newInterface{
default String getName() {
return"default method";
}
public static void show() {
System.out.println("static method");
}
}
线程不安全
public class TestSimpleDateFormat{
public static void main(String[] args) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable task = new Callable() {
@Override
public Date call() throws Exception{
return sdf.parse("20161218");
}
};
ExecutorService pool = Executors.new FixedThreadPooL(10);
List> results = new ArrayList<>();
for(inti=0; i<10; i++) {
results.add(pool.submit(task));
}
for(Future future : results) {
System.out.println(future.get());
}
}
public class DateFormatThreadLocal{
private static final ThreadLocal df = new ThreadLocal() {
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source) throws ParseException{
return df.get().parse(source);
}
}
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception{
return LocalDate.parse("20161218",dtf);
}
};
ExecutorService pool=Executors.newFixedThreadPooL(10);
List<Future<LocalDate>> results = new ArrayList<>();
for(int i=0;i<10; i++) {
results.add(pool.submit(task));
}
for(Future<LocalDate> future : results) {
System.out.println(future.get());
}
LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象, 分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法。
public class TestLocalDateTime{
@Test
public void test() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ldt2 = LocalDateTime.of(2015, 10, 19, 13, 22, 33);
System.out.println(ldt2);
LocalDateTime ldt3 = ldt.plusYears(2);
System.out.println(ldt3);
LocalDateTime ldt4 = ldt.minusMonths(2);
System.out.println(ldt4);
System.out.println(ldt.getYear());
System.out.println(ldt.getMonthValue());
System.out.println(1dt.getDayOfMonth());
System.out.println(ldt.getHour());
}
}
public class Test Local DateTime{
@Test
public void test() {
Instant ins1 = Instant.now(); //默认获取UTC时区
System.out.println(ins1);
OffsetDateTime odt = ins1.atoffset(ZoneOffset.ofHours(8));
System.out.println(odt);
System.out.println(ins1.toEpochMilli());
Instant ins2 = Instant.ofEpochSecond(1000);
System.out.println(ins2);
}
}
@Test
public void test() {
Instant ins1 = Instant.now();
try{
Thread.sleep(1000);
} catch(InterruptedException e) {
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1,ins2);
System.out.println(duration.toMillis());
LocalTime lt1 = LocalTime.now();
try{
Thread.sleep(1000);
} catch(InterruptedException e) {
}
LocalTime lt2 = LocalTime.now();
System.out.println(Duration.between(lt1,lt2).toMillis()) ;
}
@Test
public void test2() {
LocalDate ld1 = LocalDate.of(2015,1,1);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(1d1,ld2);
System.out.println(period);
}
TemporalAdjuster:时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
TemporalAdjusters:该类通过静态方法提供了大量的常用Temporal Adjuster的实现。
例如获取下个周日:
LocalDate nextSunday = LocalDate.now().with(
TemporalAdjusters.next(DayOfWeek.SUNDAY)
);
TemporalAdjuster:时间校正器
@Test
public void test() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
//自定义:下一个工作日
LocalDateTime ldt5 = ldt.with((l) ->{
LocalDateTime ldt4 = (LocalDateTime)l;
DayOfweek dow = ldt4.getDayOfWeek();
if(dow.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
}else if(dow.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
}else{
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
}
@Test
public void test() {
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
System.out.println(strDate);
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH:mm:ss");
String strDate2 = dtf2.format(ldt);
System.out.println(strDate2);
}
Java 8中加入了对时区的支持, 带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime。其中每个时区都对应着ID,地区ID都为{区域}/{城市}”的格式。例如:Asia/Shanghai等。
Zoneld:该类中包含了所有的时区信息
getAvailableZonelds() :可以获取所有时区时区信息
of(id) :用指定的时区信息获取Zone ld对象
@Test
public void test() {
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
System.out.println(ldt);
LocalDateTime ldt2 = LocalDateTime.now(zoneId.of("Europe/Tallinn"));
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Europe/Tallinn") );
System.out.println(zdt);
}
@Test
public void test() {
Set<String> set = ZoneId.getAvaiLabLeZoneIds();
set.forEach(System.out::println);
}
Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTINE)
public @interface MyAnnotations{
MyAnnotation[] value();
}
@Repeatable(MyAnnotations.class)
@Target({TYPE,FIELD,METHOD, PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,
ElementType.TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{
String value();
)
@MyAnnotation("Hello")
@MyAnnotation("World")
public void show (@MyAnnotation("abc") String str) {
}
集合的流式操作
并发
Arrays
Number和Math
IO/NIO的改进
Reflection获取形参名
String:join()
Files
Java 9 中有哪些不得不说的新特性?
模块化系统
JShell命令
多版本兼容jar包
接口的私有方法
钻石操作符的使用升级
语法改进:try语句
String存储结构变更
便利的集合特性:of()
增强的Stream APi
全新的HTTP客户端API
Deprecated的相关API
javadoc的HTML5支持
Javascript引擎升级:Nashorn
java的动态编译器
没有名为jre的子目录。
谈到Java 9大家往往第一个想到的就是Jigsaw项目。众所周知, Java已经发展超过20年(95年最初发布) , Java和相关生态在不断丰富的同时也越来越暴露出一些问题:
Java8 中规定接口中的方法除了抽象方法之外, 还可以定义静态方法和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是一个抽象类。
在 Java9 中, 接口更加的灵活和强大, 连方法的访问权限修饰符都可以声明为private的了, 此时方法将不会成为你对外暴露的API的一部分。
我们将能够与匿名实现类共同使用钻石操作符(diamond operator) 在Java 8
中如下的操作是会报错的:
Comparator<Object> com = new Comparator<>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
编译报错信息:Can not use “<>" with anonymous inner classes.
Java 8中, 可以实现资源的自动关闭, 但是要求执行后必须关闭的所有资源必须在try子句中初始化, 否则编译不通过。如下例所示:
try(InputStreamReader reader = new InputStreamReader(System.in)) {
//business
} catch(IOException e) {
e.printStackTrace();
}
java 9中资源关闭操作
InputStreamReader reader = new InputStreamReader(System.in);
try(reader) {
char[] cbuf = new char[20];
int len;
if(( len = reader.read(cbuf)) != -1) {
String str = new String(cbuf, 0, len);
System.out.println(str);
}
} catch(IOException e) {
e.printStackTrace();
}
要创建一个只读、不可改变的集合,必须构造和分配它,然后添加元素,最后包装成一个不可修改的集合。
List<String>names List = new ArrayList<>();
names List.add("Joe");
names List.add("Bob");
names List.add("Bill");
names List = Collections.unmodifiableList(names List);
System.out.println(names List);
缺点:我们一下写了五行。即:它不能表达为单个表达式。
如下操作不适用于jdk 8及之前版本, 适用于jdk 9
Map<String,Integer> map = Collections.unmodifiableMap(new HashMap<>() {
{
put("a",1);
put("b",2);
put("c",3);
}
});
map.forEach( (k,v) -> System.out.println(k + ":" + v) );
java 9新特性:集合工厂方法:创建只读集合
public void test() {
List<Integer> list1 = List.of(1, 2, 3, 4, 5);
//list1.add(6);
System.out.println(list1);
}
InputStream终于有了一个非常有用的方法:transferTo, 可以用来将数据直接传输到OutputStream, 这是在处理原始数据流时非常常见的一种用法, 如下示例。
ClassLoader cl = this.getClass().getClassLoader();
try(InputStream is = cl.getResourceAsStream("hello.txt");
OutputStream os = new FileOutputStream("src\\hello 1.txt") ) {
is.transferTo(os); //把输入流中的所有数据直接自动地复制到输出流中
} catch(IOException e) {
e.printStackTrace();
}
Optional类中stream() 的使用
List<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jerry");
list.add("Tim");
Optional<List<String>> optional = Optional.ofNullable(list);
Stream<List<String>> stream = optional.stream();
stream.flatMap( x->x.stream() ).forEach(System.out::println);
JDK 10的12个JEP
286:Local Variable Type Inference 局部变量类型推断
296:Consolidate the JDK Forest into a Single Repository JDK库的合并
304:Garbage-Collector Interface 统一的垃圾回收接口
307:Parallel Full GC for G1 为G1提供并行的Full GC
310:Application Class-Data Sharing 应用程序类数据(AppCDS) 共享
312:Thread-Local Handshakes ThreadLocal 握手交互
313:Remove the Native-Header Generation Tool(javah) 移除JDK中附带的javah工具
314:Additional Unicode Language-Tag Extensions 使用附加的Unicode语言标记扩展
316:Heap Allocation on Alternative Memory Devices 能将堆内存占用分配给用户指定的备用内存设备
317:Experimental Java-Based JIT Compiler 使用基于Java的JIT编译器
319:Root Certificates 根证书
322:Time-Based Release Versioning 基于时间的发布版本
场景一:类实例化时
作为Java开发者, 在声明一个变量时, 我们总是习惯了敲打两次变量类型, 第一次用于声明变量类型,第二次用于构造器。
LinkedHashSet<Integer> set = new Linked HashSet<>();
场景二:返回值类型含复杂泛型结构
变量的声明类型书写复杂且较长,尤其是加上泛型的使用
Iterator<Map.Entry<Integer,Student>> iterator = set.iterator();
场景三:我们也经常声明一种变量,它只会被使用一次,而且是用在下一行代码中,比如:
URL url = new URL("http://www.atguigu.com"); URLConnection connection = url.openConnection(); Reader reader = new BufferedReader(new InputStreamReader(connection.getInputStream() ));
尽管IDE可以帮我们自动完成这些代码, 但当变量总是跳来跳去的时候, 可读性还是会受到影响,因为变量类型的名称由各种不同长度的字符组成。而且有时候开发人员会尽力避免声明中间变量,因为太多的类型声明只会分散注意力,不会带来额外的好处。
java10 var 声明变量
public void test() {
//1.局部变量不赋值,就不能实现类型推断
//var num;
//2.Lambda表示式中,左边的函数式接口不能声明为var
//Supplier sup = () -> Math.random();
//vars up = () -> Math.random();
}
适用于以下情况:
局部变量的初始化
var list = new ArrayList<>();
增强for循环中的索引
for(var v:list) {
System.out.println(v);
}
传统for循环中
for(var i=0; i<100; i++) {
System.out.println(i);
}
在局部变量中使用时,如下情况不适用:
初始值为null
var s = null;
Lambda表达式
var r = () -> Hath.random();
方法引用
var r = System.out::println;
为数组静态初始化
var arr = {"a","b","c","d","e"}
局部变量类型推断的工作原理
在处理var时, 编译器先是查看表达式右边部分, 并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中。
注意:
var不是一个关键字
你不需要担心变量名或方法名会与var发生冲突, 因为var实际上并不是一个关键字,而是一个类型名,只有在编译器需要知道类型的地方才需要用到它。除此之外,它就是一个普通合法的标识符。也就是说,除了不能用它作为类名,其他的都可以,但极少人会用它作为类名。
这不是JavaScript
首先我要说明的是, var并不会改变Java是一门静态类型语言的事实。编译器负责推断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。下面是使用IntelliJ(实际上是Fernflower的反编译器) 反编译器反编译出的代码:
var url = new URL("http//www.baidu.com");
var connection = url.openConnection();
var reader = new BufferedReader(
new InputStreamReader(connection.getInputStream() ));
反编译后
URL url = new URL("http://www.atguigu.com");
URLConnection connection = url.openConnection();
BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream() ));
从代码来看,就好像之前已经声明了这些类型一样。事实上,这一特性只发生在编译阶段,与运行时无关,所以对运行时的性能不会产生任何影响。所以请放心, 这不是JavaScript。
自Java 9开始, Jdk里面为集合(List/Set/Map) 都添加了of (jdk 9新增) 和 copyOf (jdk 10新增) 方法, 它们两个都用来创建不可变的集合, 来看下它们的使用和区别。
示例1:
var list1 = List.of("Java", "Python", "C");
var copy1 = List.copyOf(list1);
System.out.println(list1==copy1); //true
示例2:
var list2 = new ArrayList<String>();
var copy2 = List.copyOf(list2);
System.out.println(list2==copy2); //false
示例1和2代码基本一致, 为什么一个为true, 一个为false?
结论:copyOf(Coll coll)
如果参数 coll 本身就是一个只读集合, 则copyOf() 返回值即为当前的coll。
如果参数 coll 不是一个只读集合, 则copyOf() 返回一个新的集合, 这个集合是只读的。
北京时间2018年9月26日,Oracle官方宜布Java 11正式发布。这是Java大版本周期变化后的第一个长期支持版本,非常值得关注。从官网即可下载,最新发布的Java11将带来ZGC、HttpClient等重要特性, 一共包含17个JEP (JDK Enhancement Proposals,JDK增强提案) 。其实,总共更新不止17个,只是我们更关注如下的17个JEP更新。
181:Nest-Based AccessControl
309:Dynamic Class-File Constants
315:Improve A arch 64 Intrinsics
318:Epsilon:ANo-OpGarbageCollector
320:Remove the Java EE and CORBA Modules
321:HTTPClient(Standard)
323:Local-Variable Syntax for Lambda Parameters
324:Key Agreement with Curve 25519 and Curve 448
327:Unicode 10
328:Flight Recorder
329:ChaCha20andPoly 1305 Cryptographic Algorithms
330:Launch Single-File Source-Code Programs
331:Low-Overhead He apP roiling
332:Transport Layer Security(TLS) 1.3
333:ZGC:AScalableLow-LatencyGarbageCollector(Experimental)
335:Deprecate theN as hom JavaScript Engine
336:Deprecate the Pack 200 Tools and AP
JDK 11是一个长期支持版本(LTS, Long-Term-Support)对于企业来说,选择11将意味着长期的、可靠的、可预测的技术路线图。其中免费的Open JDK 11确定将得到Open JDK社区的长期支持,LTS版本将是可以放心选择的版本。从JVM GC的角度, JDK 11引入了两种新的GC, 其中包括也许是划时代意义的ZGC, 虽然其目前还是实验特性, 但是从能力上来看, 这是JDK的一个巨大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部分企业核心存储等产品,如果能够保证不超过10ms的GC暂停,可靠性会上一个大的台阶,这是过去我们进行GC调优几乎做不到的,是能与不能的问题。
discription | example |
---|---|
判断字符串是否为空白 | " ".isBlank(); //true |
去除首尾空白 | " Javastack ".strip(); //“Javastack” |
去除尾部空格 | " Javastack “.stripTrailing(); //” Javastack" |
去除首部空格 | " Javastack ".stripLeading(); //"Javastack " |
复制字符串 | “Java”.repeat(3); //“JavaJavaJava” |
行数统计 | “A\nB\nC”.lines().count(); // 3 |
Optional也增加了几个非常酷的方法, 现在可以很方便的将一个Optional转换成一个Stream, 或者当一个空Optional时给它一个替代的。
新增方法 | 描述 | version |
---|---|---|
boolean isEmpty() | 判断value是否为空 | JDK11 |
ifPresentOrElse(Consumer action,Runnable emptyAction) | value非空, 执行参数1功能;如果value为空,执行参数2功能 | JDK 9 |
Optional or(Supplier extends Optional extends T>> supplier) | value为空, 返回对应的Optional;value非空, 返回形参封装的Optional; | JDK 9 |
Stream stream() | value非空, 返回仅包含此value的Stream; 否则, 返回一个空的Stream | JDK 9 |
T orElse Throw() | value非空, 返回value; 否则抛异常NoSuchElementException | JDK10 |
在var上添加注解的语法格式, 在jdk 10中是不能实现的。在JDK 11中加入了这样的语法。
错误的形式:必须要有类型, 可以加上var
Consumer<String> con1=(@Deprecated t) -> System.out.println(t.toUpperCase());
正确的形式:使用var的好处是在使用lambda表达式时给参数加上注解。
Consumer<String> con2=(@Deprecated var t) -> System.out.println(t.toUpperCase());
Sync
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/") ).build();
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
HttpResponse<String> response = client.send(request,responseBodyHandler);
String body = response.body();
System.out.println(body);
Async
HttpClient client = HttpClient.new HttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("http://127.0.0.1:8080/test/") ).build();
BodyHandler<String> responseBodyHandler = BodyHandlers.ofString();
CompletableFuture<HttpResponse<String>> sendAsync = client.sendAsync (request,responseBodyHandler);
sendAsync.thenApply(t->t.body()).thenAccept(System.out::println);
//HttpResponse response = sendAsync.get();
//String body = response.body();
//System.out.println(body);
编译
javac Javastack.java
运行
java Javastack
在我们的认知里面, 要运行一个Java源代码必须先编译, 再运行, 两步执行动作。而在未来的Java11版本中, 通过一个java命令就直接搞定了, 如以下所示:
java Javastack.java
一个命令编译运行源代码的注意点:
执行源文件中的第一个类,第一个类必须包含主方法。
并且不可以使用其它源文件中的自定义类,本文件中的自定义类是可以使用的。
废除 Nashorn javascript 引擎, 在后续版本准备移除掉, 有需要的可以考虑使用GraalVM。
优势:
- GC暂停时间不会超过10ms
- 既能处理几百兆的小堆, 也能处理几个T的大堆(OMG)
- 和G1相比,应用吞吐能力不会下降超过15%
- 为未来的GC功能和利用colord指针以及Load barriers优化奠定基础
- 初始只支持64位系统
设计目标:
ZGC的设计目标是:支持TB级内存容量, 暂停时间低(<10ms) , 对整个程序吞吐量的影响小于15%。将来还可以扩展实现机制,以支持不少令人兴奋的功能, 例如多层堆(即热对象置于DRAM和冷对象置于NV Me闪存) ,或压缩堆。
- Unicode 10
- Deprecate the Pack 200 Tools and API
- 新的Epsilon垃圾收集器
- 完全支持Linux容器(包括Docker)
- 支持G1上的并行完全垃圾收集
- 最新的HTTPS安全协议TLS 1.3
- Java Flight Recorder
在当前JDK中看不到什么?
一个标准化和轻量级的JSON API
一个标准化和轻量级的JSON API被许多Java开发人员所青睐。但是由于资金问题无法在Java当前版本中见到, 但并不会削减掉。Java平台首席架构师Mark Reinhold在JDK 9邮件列中说:“这个JEP将是平台上的一个有用的补充, 但是在计划中, 它并不像Oracle资助的其他功能那么重要, 可能会重新考虑JDK 10或更高版本中实现。”
新的货币API
对许多应用而言货币价值都是一个关键的特性, 但JDK对此却几乎没有任何支持。严格来讲, 现有的java.uti.Currency类只是代表了当前ISO 4217货币的一个数据结构,但并没有关联的值或者自定义货币。JDK对货币的运算及转换也没有内建的支持,更别说有一个能够代表货币值的标准类型了。
此前, Oracle公布的JSR 354定义了一套新的Java货币API:Java Money, 计划会在Java9中正式引入。但是目前没有出现在JDK新特性中。
不过, 如果你用的是Maven的话, 可以做如下的添加, 即可使用相关的API处理货币:
org.java money
moneta
0.9
展望