Java8新特性学习笔记

java8

Java NIO

  1. java NIO (New IO,Non-Bolcking IO)是从java1.4版本引入的一套新的IO API,可以替代标准的java io api。nio支持面向缓冲区的(io是面向流的)、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
  2. Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
  3. java.nio.channels.Channel:1.FileChannel,处理本地文件,2.SocketChannel:TCP网络编程的客户端的channel,3.ServerSocketChannel:TCP网络编程的服务器端的channel,4.DatagramChannel:UDP网络编程中发送端和接收端的Channel。
  4. jdk7对nio进行了极大的扩展,增强了对文件处理和文件系统特性的支持,称为NIO.2。因为NIO提供的一些功能,NIO已经成为文件处理中越来越重要的部分。
  5. Path、Paths、Files核心API。早起JAVA只提供了一个File类来访问文件系统,但File类的功能比较有限出错时仅返回失败,并不会提供异常信息。NIO.2引入了Path接口,Path可以看成是File类的升级版本,实际引用的资源也可以不存在。
  6. 以前IO操作这样写:
import java.io.File;
File file = new File("index.html");

在java7中这样写:

import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("index.html");
  1. 同时NIO.2在java.nio.file包下还提供了Files、Paths工具类,Files包含了大量的静态的工具方法来操作文件;Paths则包含了两个返回Path的静态工厂方法:
static Path get(String first,String ...more)//用于将多个字符串串连成路径
static Path get(URI uri)//返回指定uri对应的Path路径;
  1. java.nio.file.Files用于操作文件或目录的工具类,Files常用方法:
Path copy(Path src,Path dest,CopuOption...how):文件的复制
Path createDirectory(Path path,FileAttribute<?>...attr):创建一个目录
Path createFile(Path path,FileAttribute<?> ... arr):创建一个文件
void delete(Path path):删除一个文件/目录,如果不存在,执行报错
void deleteIfEExists(Path path):Path对应的文件/目录如果存在,执行删除
Path move(Path src,Path dest,CopyOption...how):将src移动到dest位置
long size(Path path):返回path指定文件的大小

Java网络编程

  1. Java提供了网络类库,联网的底层细节被隐藏在Java的本机安装系统中,有JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
  2. 计算机网络:把分布在不同地理区域的计算机与专门的外部设备用通信线路互连城一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。
  3. 网络编程的目的:直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。
  4. 网络编程汇总有两个主要的问题:如何准确地定位网络上一台或多台主机;定位主机上的特定的应用;找到主机后如何可靠高效地进行数据传输;
  5. 如何实现网络中的主机互相通信:1.通信双方地址:ip+端口号。2.一定的规则(即网络通信协议,两套模型):OSI参考模型(模型过于理想化,未能在因特网上进行广泛推广),TCP\IP参考模型(TCP\OP协议):事实上的国际标准。
  6. OSI参考模型:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。TCP\IP参考模型:应用层(HTTP、FTP、Telnet、DNS...),传输层(TCP,UDP),网络层(IP,ICMP,ARP),物理+数据链路层(Link)。

lambda表达式

  1. 举例:(o1,o2)-> Integer.compare(o1,o2);

  2. 格式:->:lambda操作符或箭头操作符,->左边:lamdba形参列表(其实就是接口中的抽象方法的形参列表),->右边:lamdba体(其实就是重写的抽象方法的方法体)

  3. 总结:->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参只有一个参数,其一对()也可以省略。->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句,省略这一对{}和return关键字);

  4. lambda表达式的本质:作为函数式接口的实例。

  5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。

lambda表达式的使用:(分为6种情况)

  1. 无参,无返回值:Runnable r1 = ()->{System.out.pritln("Hello Lambda!");};
  2. Lambda需要一个参数,但是没有返回值:Consumer<String> con = (String str) -> {System.out.pritln(str);};
  3. 数据类型可以省略,因为可由编译器推断得出,称为“类型推断”:Consumer<String> con = (str) -> {System.out.pritln(str);};
  4. lambda若只需要一个参数时,参数的小括号可以省略:Consumer<String> con = str -> {System.out.pritln(str);};
  5. lambda需要两个或两个以上的参数,多条执行语句,并且可以有返回值:
Consumer<Integer> con =(x,y)->{
    System.out.pritln("实现函数式接口方法!");
    return Integer.compare(x,y);
};
  1. 当lambda体只有一条语句时,return与大括号若有,都可以省略:Consumer<Integer> con =(x,y)->Integer.compare(x,y);

函数式接口

  1. 使用说明:如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口。lambda表达式的本质:作为函数式接口的实例。
  2. java8中内置的lambda表达式提供的4个基本的函数式接口:Cousumer消费型接口,参数类型T,返回类型void,用途:对类型为T的对象应用操作,包含方法void accept(T t);Supplier供给型接口,参数类型无,返回类型T,用途:返回类型为T的对象,包含方法:T get();Function<T,R>函数型接口,参数类型T,返回类型R,用途:对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t);Predicate断定型接口,参数类型T,返回类型boolean,用途:确定类型为T的对象是否满足某约束,并返回boolean值。包含方法:boolean test(T t);
  3. 总结:
    3.1 何时使用lambda表达式:当需要对一个函数式接口实例化的时候,可以使用lambda表达式。
    3.2 何时使用给定的函数式接口:如果我们开发中需要定义一个函数式接口,首先看看在已有的jdk提供的函数式接口是否提供了能满足需求的函数式接口。如果有,直接调用即可,不需要自己再定义。

方法引用

  1. 使用情景:当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用!
  2. 方法引用:本质上就是lambda表达式,而lambda表达式作为函数式接口的实例,所以方法引用也就是函数式接口的实例。
  3. 使用格式: 类(或对象):: 方法名
  4. 具体分为如下的三种情况:1.对象 ::非静态方法。2.类 ::静态方法。3.类 ::非静态方法。
  5. 方法引用使用的要求:要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对于上述的1和2)。
  6. 使用建议:如果给函数式接口提供实例,恰好满足方法引用的使用情景,大家就可以考虑使用方法引用给函数式接口提供实例。如果大家不熟悉方法引用,那么还可以使用lambda表达式。
  7. 使用举例:
public void test(){
    Comparator<String> com1 = (s1,s2)->s1.compareTo(s2);
    System.out.println(com1.compare("abc","abd"));
    System.out.println("*********************");
    Comparator<String> com2 = String :: compareTo;
    System.out.println(com2.compare("abd","abm"));
}
  1. 构造器引用格式:和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。抽象方法的返回值类型即为构造器所属的类的类型。
    //类名::new;
  2. 构造器引用举例://Supplier中的T get(),Employee的空参构造器:Employee()
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());
}
  1. 数组引用格式: type[]::new
  2. 数组引用举例: Function<Integer,Integer[]> fun = (n) -> new Integer[n];等同于:Function<Integer,Integer[]> fun = Integer[]::new;

Stream API

  1. Stream关注的是对数据的运算,与CPU打交道。集合关注的是数据的存储,与内存打交道
  2. java8提供了一套api,使用这套api可以对内存中的数据进行过滤、排序、映射、归约等操作,类似于SQL对数据库中表的相关操作。
  3. 注意点:Stream自己不会存储元素;Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。Stream操作是延迟执行的,这意味着他们会等到需要结果的时候才执行。
  4. Stream执行流程:Stream实例化,一系列的中间操作(过滤、映射、...),终止操作。
  5. 说明:一个中间操作链,对数据源的数据进行处理,一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用。
  6. 为什么要使用Stream API:实际开发中,项目多数数据源都来自mysql,Oracle等。但来mongoDB,Redis这些nosql的数据就需要java层面去处理。
  7. Stream和Collection的区别:Collection是一种静态的内存数据结构,而Stream是有关计算的。前者主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。

Optinoal类

  1. Optional类(java.util.Optional)是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
  2. Optional提供很多方法,这样我们就不用显式进行空值检测。
  3. 创建Optional类对象的方法:Optional.of(T t):创建一个Optional实例,t必须非空;Optional.empty(),创建一个空的Optional实例;Optional.ofNullable(T t),t可以为null;
  4. 判断Optional容器中是否包含对象:boolean isPresent(),判断是否包含对象;void ifPresent(Consumer<? super T>consumer):如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
  5. 获取Optional容器的对象:T get(),如果调用对象包含值,返回该值,否则抛异常;T orElse(T other):如果有值则将其返回,否则返回指定的other对象;T orElseGet(Supplier<? extends T>other):如果有值则将其返回,否则返回由Supplier接口实现提供的对象;T orElseThrow(Supplier<? extends X>exceptionSupplier):如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
  6. 常用方法:
public class OptionalTest{
    @Test
    public void test1(){
        //empty()创建的Optional对象内部的value=null
        Optional<Object> op1 = Optional.empty();
        if(!op1.isPresent()){//Optional封装的数据是否包含数据
            System.out.println("数据为空");
        }
        System.out.println(op1);
        System.out.println(op1.isPresent());
        //如果Optional封装的数据vale为空,则get()报错。否则value不为空时,返回value
        System.out.println(op1.get());
    }
    @Test
    public void test2(){
        String str = "hello";
        //of(T t):封装数据t生成Optional对象。要求t非空,否则报错。
        Optional<String> op1 = Optional.of(str);
        //get()通常与of()方法搭配使用。用于获取内部的封装的数据value
        String str1 = op1.get();
        System.out.println(str1);
    }
    @Test
    public void test3(){
        String str = "beijing";
        //ofNullable(T t):封装数据t赋给Optional内部的value。不要求t非空
        Optional<String> op1 = Optional.ofNullable(str);
        //orElse(T t1):如果Optional内部的value非空,则返回此value值。如果value为空,则返回t1
        String str2 = opq.orElse("shanghai");
        System.out.println(str2);//ofNullable(T t)与orElse(T t1)通常搭配使用
    }
}
  1. 练习:保证如下的方法执行中不会出现空指针异常
//使用Optional类的getGirlName():
public String getGirlName(Boy boy){
    Optional<Boy> boyOptional = Optional.ofNullable(boy);
    //此时的boy1一定非空
    Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴")));
    Girl girl = boy1.getGirl();
    Optional<Girl> girlOptional = Optional.ofNullable(girl);
    //girl1一定非空
    Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));
    return girl1.getName();
}
@Test
public void test5(){
    Boy boy = null;
    boy = new Boy();
    boy = new Boy(new Girl("小苍"));
    String girlName = getGirlName2(boy);
    System.out.println(girlName);
}

posted on 2022-08-14 23:23  张少凯  阅读(64)  评论(0编辑  收藏  举报

导航