JDK 的前世今生:细数 Java5 - 15 的那些经典特性
可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
7.静态导入
通过 import static 类,就可以使用类里的静态变量或方法。看一下例子哈~
import static java.lang.System.out; //静态导入 System 类的静态变量 out
public class Test {
public static void main(String[] args) throws Exception {
String str1 = "私信资料,领一线大厂面试专题";
System.out.println(str1); //常规写法
out.println(str1); //静态导入,可以直接使用 out 输出
}
}
8. 线程并发库(JUC)
JDK5 丰富了线程处理功能,java.util.concurrent 包提供了以下的类、接口:
?
线程池:ExecutorService 接口
线程护斥:Lock 类
线程通信:Condition 接口
同步队列:ArrayBlockingQueue 类
同步集合:ConcurrentHashMap 类
?
Java 6 新特性
1.Desktop 类和 SystemTray 类
JDK 6 在 java.awt 包下,新增了两个类:Desktop 类和 SystemTray 类
?
「Desktop 类」: 用来打开系统默认浏览器浏览指定的 URL,打开系统默认邮件客户端发邮件等
「SystemTray 类」:用来在系统托盘区创建一个托盘程序,如果在微软的 Windows 上,它被称为“任务栏”状态区域。
?
//获取 Desktop 实例
Desktop desktop = Desktop.getDesktop();
desktop.browse(URI.create("https://www.baidu.com"));
2. 使用 JAXB2 来实现对象与 XML 之间的映射
JAXB,即 Java Architecture for XML Binding,可以实现对象与 XML 之间的映射,常用注解如下:
?
@XmlRootElement:注解在类上面,对应 xml 的跟元素,使用 name 属性定义根节点的名称。
@XmlElement:指定一个字段或 get/set 方法映射到 xml 的节点,使用 name 属性定义这个根节点的名称。
@XmlAttribute:将 JavaBean 对象的属性映射为 xml 的属性,使用 name 属性为生成的 xml 属性指定别名。
@XmlAccessorType:定义映射这个类中的何种类型都需要映射到 xml。
@XmlSchema: 将包映射到 XML 名称空间
?
「看个例子吧~」
public class JAXB2XmlTest {
public static void main(String[] args) throws JAXBException, IOException {
List<Singer> list = new ArrayList<>();
list.add(new Singer("jay", 8));
list.add(new Singer("eason", 10));
SingerList singerList = new SingerList();
singerList.setSingers(list);
String str = JAXB2XmlTest.beanToXml(singerList, SingerList.class);
String path = "C:\jay.txt";
BufferedWriter bfw = new BufferedWriter(new FileWriter(new File(path)));
bfw.write(str);
bfw.close();
}
private static String beanToXml(Object obj, Class<?> load) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(load);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "GBK");
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
}
public class Singer {
private String name;
private int age;
public Singer(String name, int age) {
this.name = name;
this.age = age;
}
@XmlAttribute(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlAttribute(name="age")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@XmlRootElement(name="list")
public class SingerList {
private List<Singer> singers;
@XmlElement(name="singer")
public List<Singer> getSingers() {
return singers;
}
public void setSingers(List<Singer> singers) {
this.singers = singers;
}
}
「运行效果:」
<?xml version="1.0" encoding="GBK" standalone="yes"?>
<list>
<singer age="8" name="jay"/>
<singer age="10" name="eason"/>
</list>
3.轻量级 Http Server API
JDK 6 中提供了简单的 Http Server API,可以构建嵌入式 Http 服务器,同时支持 Http 和 Https 协议。HttpServer 会调用 HttpHandler 实现类的回调方法来处理客户端请求,这里用户只需实现 HttpHandler 接口就可以了。
/**
根据 Java 提供的 API 实现 Http 服务器
*/
public class MyHttpServer {
/**
@param args
@throws IOException
*/
public static void main(String[] args) throws IOException {
//创建 HttpServer 服务器
HttpServer httpServer = HttpServer.create(new InetSocketAddress(8080), 10);
//将 /jay 请求交给 MyHandler 处理器处理
httpServer.createContext("/", new MyHandler());
httpServer.start();
}
}
public class MyHandler implements HttpHandler {
public void handle(HttpExchange httpExchange) throws IOException {
//请求头
Headers headers = httpExchange.getRequestHeaders();
Set<Map.Entry<String, List<String>>> entries = headers.entrySet();
StringBuffer response = new StringBuffer();
for (Map.Entry<String, List<String>> entry : entries){
response.append(entry.toString() + "\n");
}
//设置响应头属性及响应信息的长度
httpExchange.sendResponseHeaders(200, response.length());
//获得输出流
OutputStream os = httpExchange.getResponseBody();
os.write(response.toString().getBytes());
os.close();
}
}
4. 插入式注解处理 API
?
JDK 6 提供了插入式注解处理 API,可以让我们定义的注解在编译期而不是运行期生效,从而可以在编译期修改字节码。lombok 框架就是使用该特性来实现的,Lombok 通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString 等方法,大大简化了代码的开发。
?
5. STAX
STAX,是 JDK6 中一种处理 XML 文档的 API。
public class STAXTest {
public static void main(String[] args) throws Exception {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
XMLEventReader xmlEventReader = xmlInputFactory.createXMLEventReader(new FileInputStream("C:\jay.xml"));
XMLEvent event = null;
StringBuffer stringBuffer = new StringBuffer();
while (xmlEventReader.hasNext()) {
event = xmlEventReader.nextEvent();
stringBuffer.append(event.toString());
}
System.out.println("xml 文档解析结果:");
System.out.println(stringBuffer);
}
}
「运行结果:」
xml 文档解析结果:
<?xml version="1.0" encoding='GBK' standalone='yes'?><list>
<singer name='jay' age='8'></singer>
<singer name='eason' age='10'></singer>
</list>ENDDOCUMENT
6. Common Annotations
?
Common annotations 原本是 Java EE 5.0(JSR 244)规范的一部分,现在 SUN 把它的一部分放到了 Java SE 6.0 中。随着 Annotation 元数据功能加入到 Java SE 5.0 里面,很多 Java 技术都会用 Annotation 部分代替 XML 文件来配置运行参数。
?
以下列举 Common Annotations 1.0 里面的几个 Annotations:
@Generated:用于标注生成的源代码
@Resource: 用于标注所依赖的资源,容器据此注入外部资源依赖,有基于字段的注入和基于 setter 方法的注入两种方式 。
@Resources:同时标注多个外部依赖,容器会把所有这些外部依赖注入
@PostConstruct:标注当容器注入所有依赖之后运行的方法,用来进行依赖注入后的初始化工作,只有一个方法可以标注为 PostConstruct 。
@PreDestroy:当对象实例将要被从容器当中删掉之前,要执行的回调方法要标注为 PreDestroy
7. Compiler API
javac 编译器可以把.java 的源文件编译为.class 文件,JDK 6 的新特性 Compiler API(JSR 199)也可以动态编译 Java 源文件。
public class CompilerApiTest {
public static void main(String[] args) throws Exception {
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null,null,null);
Iterable<? extends JavaFileObject> javaFileObjects = standardJavaFileManager.getJavaFileObjects("C:\Singer.java");
javaCompiler.getTask(null, standardJavaFileManager, null, null, null, javaFileObjects).call();
standardJavaFileManager.close();
}
}
运行结果:会在 C 目录生成 Singer.class 文件
8. 对脚本语言的支持(如: ruby, groovy, javascript)
JDK6 增加了对脚本语言的支持(JSR 223),原理是将脚本语言编译成字节码,这样脚本语言也能享用 Java 平台的诸多优势,包括可移植性,安全等。JDK6 实现包含了一个基于 Mozilla Rhino 的 脚本语言引擎,因此可以支持 javascript,当然 JDK 也支持 ruby 等其他语言
public class JavaScriptTest {
public static void main(String[] args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
String script;
try {
script = "print('Hello')";
engine.eval(script);// 执行脚本
}catch (Exception e) {
e.printStackTrace();
}
}
}
//output
Hello
Java 7 新特性
1.switch 支持 String 字符串类型。
String singer = "jay";
switch (singer) {
case "jay" :
System.out.println("周杰伦");
break;
case "eason" :
System.out.println("陈奕迅");
break ;
default :
System.out.println("其他");
break ;
}
2.try-with-resources,资源自动关闭
JDK 7 之前:
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt"));
try {
return br.readLine();
} finally {
br.close();
}
JDK 7 之后:
/*
声明在 try 括号中的对象称为资源,在方法执行完毕后会被自动关闭
*/
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
return br.readLine();
}
3. 整数类型如(byte,short,int,long)能够用二进制来表示
//0b 或者 0B 表示二进制
int a = 0b010;
int b = 0B010;
4. 数字常量支持下划线
int a = 11_11;//a 的值为 1111,下划线不影响实际值,提升可读性
5. 泛型实例化类型自动推断,即”<>”
JDK 7 之前:
Map<String, List<String>> map = new HashMap<String, List<String>>();
JDK 7 之后:
//不须声明类型,自动根据前面<>推断其类型
Map<String, List<String>> map = new HashMap<>();
6.一个 catch 中捕获多个异常类型,用(|)分隔开
JDK 7 之前
try{
//do something
} catch (FirstException e) {
logger.error(e);
} catch (SecondException e) {
logger.error(ex);
}
JDk 7 之后
try{
//do something
} catch (FirstException | SecondException e) {
logger.error(e);
}
7. 增强的文件系统
Java7 提供了全新的 NIO2.0 API,方便文件管理的编码。如,可以在 java.nio.file 包下使用 Path、Paths、Files、WatchService 等常用类型。
Path path = Paths.get("C:\jay\七里香.txt"); //创建 Path 对象
byte[] bytes= Files.readAllBytes(path); //读取文件
System.out.println(path.getFileName()); //获取当前文件名称
System.out.println(path.toAbsolutePath()); // 获取文件绝对路径
System.out.println(new String(bytes, "utf-8"));
8. Fork/join 框架
Java7 提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。
Fork/join 计算 1-1000 累加值:
public class ForkJoinPoolTest {
private static final Integer DURATION_VALUE = 100;
static class ForkJoinSubTask extends RecursiveTask<Integer>{
// 子任务开始计算的值
private Integer startValue;
// 子任务结束计算的值
private Integer endValue;
pri
vate ForkJoinSubTask(Integer startValue , Integer endValue) {
this.startValue = startValue;
this.endValue = endValue;
}
@Override
protected Integer compute() {
//小于一定值 DURATION,才开始计算
if(endValue - startValue < DURATION_VALUE) {
System.out.println("执行子任务计算:开始值 = " + startValue + ";结束值 = " + endValue);
Integer totalValue = 0;
for (int index = this.startValue; index <= this.endValue; index++) {
totalValue += index;
}
return totalValue;
} else {
// 将任务拆分,拆分成两个任务
ForkJoinSubTask subTask1 = new ForkJoinSubTask(startValue, (startValue + endValue) / 2);
subTask1.fork();
ForkJoinSubTask subTask2 = new ForkJoinSubTask((startValue + endValue) / 2 + 1 , endValue);
subTask2.fork();
return subTask1.join() + subTask2.join();
}
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// Fork/Join 框架的线程池
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Integer> taskFuture = pool.submit(new ForkJoinSubTask(1,1000));
Integer result = taskFuture.get();
System.out.println("累加结果是:" + result);
}
}
运行结果:
...
执行子任务计算:开始值 = 189;结束值 = 250
执行子任务计算:开始值 = 251;结束值 = 313
执行子任务计算:开始值 = 314;结束值 = 375
执行子任务计算:开始值 = 376;结束值 = 438
执行子任务计算:开始值 = 439;结束值 = 500
执行子任务计算:开始值 = 501;结束值 = 563
执行子任务计算:开始值 = 564;结束值 = 625
执行子任务计算:开始值 = 626;结束值 = 688
执行子任务计算:开始值 = 689;结束值 = 750
执行子任务计算:开始值 = 751;结束值 = 813
执行子任务计算:开始值 = 814;结束值 = 875
执行子任务计算:开始值 = 876;结束值 = 938
执行子任务计算:开始值 = 939;结束值 = 1000
累加结果是:500500
Java 8 新特性
1.lambada 表达式
Lambda 允许把函数作为一个方法的参数,传递到方法中
语法格式:
(parameters) -> expression 或 (parameters) ->{ statements; }
代码示例:
Arrays.asList("jay", "Eason", "SHE").forEach(
( String singer ) -> System.out.print( singer + ",") );
2. 函数式接口
Lambda 的设计者为了让现有的功能与 Lambda 表达式很好兼容,设计出函数式接口。
函数式接口是指只有一个函数的接口,可以隐式转换为 lambada 表达式。
Java 8 提供了注解 @FunctionalInterface,显示声明一个函数式接口。
java.lang.Runnable 和 java.util.concurrent.Callable 是函数式接口的例子~
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
3. 方法引用
方法引用提供了非常有用的语法,可以直接引用已有 Java 类或对象(实例)的方法或构造器。它与 Lambda 表达式配合使用,可以减少冗余代码,使代码更加简洁。
//利用函数式接口 Consumer 的 accept 方法实现打印,Lambda 表达式如下
Consumer<String> consumer = x -> System.out.println(x);
consumer.accept("jay");
//引用 PrintStream 类(也就是 System.out 的类型)的 println 方法,这就是方法引用
consumer = System.out::println;
consumer.accept("私信资料,领一线大厂面试专题");
4. 默认方法
默认方法就是一个在接口里面有了一个实现的方法。它允许将新方法添加到接口,但不强制实现了该接口的类必须实现新的方法。
public interface ISingerService {
// 默认方法
default void sing(){
System.out.println("唱歌");
}
void writeSong();
}
//JaySingerServiceImpl 不用强制实现 ISingerService 的默认 sing()方法
public class JaySingerServiceImpl implements ISingerService {
@Override
public void writeSong() {
System.out.println("写了一首七里香");
}
}
5.Stream API
Stream API,支持对元素流进行函数式操作,它集成在 Collections API 中,可以对集合进行批量操作。常用 API:
filter 筛选
map 流映射
reduce 将流中的元素组合起来
collect 返回集合
sorted 排序
flatMap 流转换
limit 返回指定流个数
distinct 去除重复元素
public class Singer {
private String name;
private Integer songNum;
private Integer age;
...
}
List<Singer> singerList = new ArrayList<Singer>();
singerList.add(new Singer("jay", 11, 36));
singerList.add(new Singer("eason", 8, 31));
singerList.add(new Singer("JJ", 6, 29));
List<String> singerNameList = singerList.stream()
.filter(singer -> singer.getAge() > 30) //筛选年龄大于 30
.sorted(Comparator.comparing(Singer::getSongNum)) //根据歌曲数量排序
.map(Singer::getName) //提取歌手名字
.collect(Collectors.toList()); //转换为 List
6. Optional
Java 8 引入 Optional 类,用来解决 NullPointerException。Optional 代替 if…else 解决空指针问题,使代码更加简洁。
if…else 判空
Singer singer = getSingerById("666");
if (singer != null) {
String name = singer.getName();
System.out.println(name);
}
Optional 的判空
Optional<Singer> singer = Optional.ofNullable(getSingerById("666"));
singer.ifPresent(s -> System.out.println(s.getName()));
7. Date Time API
JDK 8 之前的日期 API 处理存在非线程安全、时区处理麻烦等问题。Java 8 在 java.time 包下提供了新的日期 API,简化了日期的处理~
LocalDate today = LocalDate.now();
int year = today.getYear();
System.out.println("今年是" + year);
//是否闰年
System.out.println("今年是不是闰年:" + today.isLeapYear());
LocalDateTime todayTime = LocalDateTime.now();
System.out.println("当前时间" + todayTime);
//时区指定
System.out.println("美国时间:" + ZonedDateTime.of(todayTime,ZoneId.of("America/Los_Angeles")));
LocalDate specailDate = LocalDate.of(2020, 6, 20);
LocalDate expectDate = specailDate.plus(100, ChronoUnit.DAYS);
System.out.println("比较特别的一天" + specailDate);
System.out.println("特殊日期的 100 天" + expectDate);
8. 重复注解
重复注解,即一个注解可以在一个类、属性或者方法上同时使用多次;用 @Repeatable 定义重复注解
@Repeatable(ScheduleTimes.class)
public @interface ScheduleTime {
String value();
}
public @interface ScheduleTimes {
ScheduleTime[] value();
}
public class ScheduleTimeTask {
@ScheduleTime("10")
@ScheduleTime("12")
public void doSomething() { }
}
9. Base64
Java 8 把 Base64 编码的支持加入到官方库中~
String str = "私信资料,领一线大厂面试专题";
String encoded = Base64.getEncoder().encodeToString(str.getBytes( StandardCharsets.UTF_8));
String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
10. JVM 的新特性
使用元空间 Metaspace 代替持久代(PermGen space),JVM 参数使用-XX:MetaSpaceSize 和-XX:MaxMetaspaceSize 设置大小。
Java 9 新特性
1. java 模块系统
什么是模块化?
?
一个大型系统,比如一个商城网站,它会包含很多模块的,如:订单模块,用户信息模块,商品信息模块,广告位模块等等。各个模块之间会相互调用。如果每个模块单独运行都会带动其他所有模块,性能非常低效。但是,如果某一模块运行时,只会启动它所依赖的模块,性能大大提升。这就是 JDK 9 模块化的思想。
?
什么是 JDK 9 模块化?
?
Java 平台模块系统,即 Project Jigsaw,把模块化开发实践引入到了 Java 平台中。在引入了模块系统之后,JDK 被重新组织成 94 个模块。Java 应用可以通过新增的 jlink 工具,创建出只包含所依赖的 JDK 模块的自定义运行时镜像。这样可以极大的减少 Java 运行时环境的大小。
?
Java 9 模块的重要特征:
?
在其工件(artifact)的根目录中包含了一个描述模块的 module-info.class 文 件。
工件的格式可以是传统的 JAR 文件或是 Java 9 新增的 JMOD 文件。
这个文件由根目录中的源代码文件 module-info.java 编译而来。
该模块声明文件可以描述模块的不同特征。
?
在 module-info.java 文件中,我们可以用新的关键词 module 来声明一个模块,如下所示。下面给出了一个模块 com.mycompany.mymodule 的最基本的模块声明
module com.jay.sample { //关键词 module 来声明一个模块
exports com.jay.sample; //使用 exports 可以声明模块对其他模块所导出的包。
requires com.jay.common; //使用 requires 可以声明模块对其他模块的依赖关系。
}
2. 不可变集合工厂方法
为了创建不可变集合,JDK9 之前酱紫的:
List<String> stringList = new ArrayList<>();
stringList.add("私信资料:");
stringList.add("领一线大厂面试专题");
List<String> unmodifiableList = Collections.unmodifiableList(stringList);
JDK 9 提供了 List.of()、Set.of()、Map.of()和 Map.ofEntries()等工厂方法来创建不可变集合:
List<String> unmodifiableList = List.of("私信资料:","领一线大厂面试专题");
3. 接口支持私有方法
JDK 8 支持在接口实现默认方法和静态方法,但是不能在接口中创建私有方法,为了避免了代码冗余和提高阅读性,JDK 9 在接口中支持私有方法。
public interface IPrivateInterfaceTest {
//JDK 7 之前
String a = "jay";
void method7();
//JDK 8
default void methodDefault8(){
System.out.println("JDK 8 新特性默认方法");
}
static void methodStatic8() {
System.out.println("JDk 8 新特性静态方法");
}
//Java 9 接口支持私有方法
private void method9(){}
}
4. ?钻石操作符升级
钻石操作符是在 java 7 中引入的,可以让代码更易读,但它不能用于匿名的内部类。
在 java 9 中, 它可以与匿名的内部类一起使用,从而提高代码的可读性。
//JDK 5,6
Map<String, String> map56 = new HashMap<String,String>();
//JDk 7,8
Map<String, String> map78 = new HashMap<>();
//JDK 9 结合匿名内部类的实现
Map<String, String> map9 = new HashMap<>(){};
5. Optional 类改进
java 9 中,java.util.Optional 添加了很多新的有用方法,如:
stream()
ifPresentOrElse()
or()
ifPresentOrElse 方法的改进就是有了 else,接受两个参数 Consumer 和 Runnable。
import java.util.Optional;
public class OptionalTest {
public static void main(String[] args) {
Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
optional = Optional.empty();
optional.ifPresentOrElse( x -> System.out.println("Value: " + x),() ->
System.out.println("Not Present."));
}
}
6. 多版本兼容 Jar 包
?
很多公司使用的 JDK 都是老版本的,JDK6、JDk5 ,甚至 JDk4 的,不是他们不想升级 JDk 版本,而是担心兼容性问题。JDK 9 的一个新特性,多版本兼容 Jar 包解决了这个问题。举个例子:假设你一直用的是小米 8,已经非常习惯它的运行流程了,突然出来小米 9,即使小米 9 很多新功能引人入胜,但是有些人不会轻易买小米 9,因为已经已经习惯小米 8 的流程。同理,为什么很多公司不升级 JDK,就是在此。但是呢,JDK 9 的这个功能很强大,它可以让你的版本升级到 JDK 9,但是还是老版本的运行流程,即在老的运行流程继承新的功能~
?
7. JShell 工具
jShell 工具相当于 cmd 工具,然后呢,你可以像在 cmd 工具操作一样,直接在上面运行 Java 方法,Java 语句等~
jshell> System.out.println("私信资料,领一线大厂面试专题");
私信资料,领一线大厂面试专题
8. try-with-resources 的改进
JDK 9 对 try-with-resources 异常处理机制进行了升级~
//JDK 7,8
try (BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")) {
br.readLine();
}catch(IOException e){
log.error("IO 异常,e:{}",e);
}
//JDk 9
BufferedReader br = new BufferedReader(new FileReader("d:七里香.txt")
try(br){
br.readLine();
}catch(IOException e){
log.error("IO 异常,e:{}",e);
}
9. Stream API 的改进
JDK 9 为 Stream API 引入以下这些方法,丰富了流处理操作:
takeWhile()
dropWhile()
iterate
ofNullable
「takeWhile」
使用一个断言(Predicate 接口)作为参数,返回给定 Stream 的子集直到断言语句第一次返回 false
// 语法格式
default Stream<T> takeWhile(Predicate<? super T> predicate)
//代码示例
Stream.of(1,2,3).takeWhile(s-> x<2)
.forEach(System.out::println);
//输出
1
「dropWhile」
与 takeWhile()作用相反,使用一个断言(Predicate 接口)作为参数,直到断言语句第一次返回 true,返回给定 Stream 的子集
//语法
default Stream<T> dropWhile(Predicate<? super T> predicate)
//代码示例
Stream.of(1,2,3).dropWhile(s-> x<2)
.forEach(System.out::println);
//输出
2
3
「iterate」
iterate() 方法能够返回以 seed(第一个参数)开头,匹配 Predicate(第二个参数)直到返回 false,并使用第三个参数生成下一个元素的元素流。
//语法
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
//代码示例
IntStream.iterate(2, x -> x < 10, x -> x*x).forEach(System.out::println);
//输出
2
4
「ofNullable」
如果指定元素为非 null,则获取一个元素并生成单个元素流,元素为 null 则返回一个空 Stream。
//语法
static <T> Stream<T> ofNullable(T t)
//代码示例
Stream<Integer> s1= Stream.ofNullable(100);
s1.forEach(System.out::println)
Stream<Integer> s2 = Stream.ofNullable(null);
s2.forEach(System.out::println)
//输出
100
10.其他
?
HTTP 2 客户端 (支持 WebSocket 和 HTTP2 流以及服务器推送)
进程 API(控制和管理操作系统进程)
String 底层存储结构更改(char[]替换为 byte[])
标识符添加限制( String _ ="hello"不能用)
响应式流 API (支持 Java 9 中的响应式编程)
?
Java 10 新特性
1.局部变量类型推断
JDK 10 增加了局部变量类型推断(Local-Variable Type Inference)功能,让 Java 可以像 Js 里的 var 一样可以自动推断数据类型。Java 中的 var 是一个保留类型名称,而不是关键字。
JDK 10 之前
List<String> list = new ArrayList<String>();
Stream<Integer> stream = Stream.of(1, 2, 3);
JDK 10 之后
var list = new ArrayList<String>(); // ArrayList<String>
var stream = Stream.of(1, 2, 3);
var 变量类型推断的使用也有局限性,仅**「局限」**于以下场景:
具有初始化器的局部变量
增强型 for 循环中的索引变量
传统 for 循环中声明的局部变量
而**「不能用于」**
推断方法的参数类型
构造函数参数类型推断
推断方法返回类型
字段类型推断
捕获表达式
2. 不可变集合的改进
JDK 10 中,List,Set,Map 提供了一个新的静态方法 copyOf(Collection<? extends E> coll),它返回 Collection 集合一个不可修改的副本。
JDK 源码:
static <E> List<E> copyOf(Collection<? extends E> coll) {
return ImmutableCollections.listCopy(coll);
}
使用实例:
var oldList = new ArrayList<String>();
评论