JAVA中级

文章目录

多线程

一个Java.exe至少有三个线程:main()主线程,gc()垃圾回收,异常处理

线程的资源

请添加图片描述
其中线程独享自己的虚拟机栈和程序计数器,共享一个进程的方法区,堆和本地方法栈

创建线程的方式

继承Thread类,线程不安全,数据不共享

1.创新一个继承于Thread的子类线程
2.重写Thread类中run()方法
3.在主线程中创建Thread类的子类对象
4.通过此对象调用start()方法:
(4.1)start方法:启动当前线程并调用当前线程run()方法。
(4.2)不能直接在主线程调用子线程run方法启动线程,会继续在主线程执行。
(4.3)不可以让已经start()的线程再次start(),会报线程错误。

实现Runnable接口,线程不安全,天然共享数据

1.创建一个实现Runnable接口的类
2.实现类实现Runnable接口的run方法
3.创建实现类对象(实际运行的线程)
4.将此对象作为参数传递到Thread类构造器中,创建Thread对象
5.通过Thread对象调用start(),调用实现类的run方法

总结:
1方法因为单继承,能实现功能受限制;
1方法不能实现共享数据,需要加static关键字
Thread类也实现了Runnable方法。

三个关键结构:
Runnable接口,实现类对象,Thread对象
三个关键步骤:
1.实现类实现Runnable接口,创建实现类对象;
2.作为参数传递给Thread创建Thread对象,更新Thread中属性Runnable引用
3.在Thread的run方法中判断属性Runnable引用是否为空,不为空则调用Runnable引用对象的run方法,否则调用自己的run方法。

Thread常用方法

1.start():启动子线程
在主线程中调用,启动当前线程并调用当前线程run()方法
2,run():子线程执行的内容
在子线程声明中重写,或在匿名子类中重写。
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程名字
5.setName():设定线程名字
6.yeild():主动释放资源,自己仍然可能继续抢到。
7.join():在线程a中调用线程b的join方法,a线程阻塞,直到b线程运行完,恢复到就绪态。
8.stop():已过时,强制结束当前线程
9.sleep(long millitime):阻塞当前线程多长时间
10.isAlive():判断当前线程是否存活。

Thread优先级

JAVA线程调度方式:
1.同优先级组成先进先出队列,先到先服务,时间片轮转
2.高优先级,使用优先级调度抢占式:高优先级可以抢占低优先级,当时高优先级线程的时间片用完仍旧会执行低优先级的线程。
属性
最大优先级10:MAX_PRIORITY10
最小优先级1:MIN_PRIORITY1
默认优先级5:NORM_PRIORITY
方法
返回当前线程优先级: getPriority()
设定优先级:setPriority(int p)

JAVA实现线程同步

synchronized 同步代码块

synchronized(同步监视器){
//需要同步的代码
}
1.操作共享数据的代码即为需要被包裹的代码
2.共享数据
3.同步监视器,任何一个类对象都可以被当成锁,但多个线程要共用同一个锁。
4.但是每次只有一个线程操作共享数据,相当于一个线程执行,效率低。
5.实现runnable接口时可以在实现类的run方法中使用this充当同步监视器

synchronized同步方法

1.同步方法仍然使用同步监视器,只是不需要显示声明
2.非静态的同步方法默认是this,静态的同步方法默认是当前类本身。

手动上锁JKD5.0新增 ReentrantLock

1.实现类中,实例化锁:
private ReentrantLock lock = new ReentrantLock();
2.将需要同步的代码放入try-finally中
3.在想上锁的位置调用锁的lock()方法,再需要释放锁的时候调用unlock()方法。
可以灵活上锁解锁
推荐:lock->同步代码块->同步方法

线程通信

1.必须写在同步代码块和同步方法中
2.必须是同步监视器调用三个方法
方法:
wait();一旦执行此方法线程就陷入阻塞,并释放同步监视器
notify();唤醒一个被wait阻塞的线程,多个线程唤醒优先级高的
notifyAll();唤醒所有wai阻塞的t线程

wait和sleep的异同
相同:都可以阻塞线程
不同:
1.Thread类中声明sleep,Object类中声明wait
2.sleep可以在任何场景下使用,wait必须在同步代码块中
3.都使用在同步代码块中,sleep不会释放锁,wait会释放锁。

JDK5.0新增创建线程方式

Callable接口

步骤
1.创建实现了Callable接口的实现类
2.实现类重写Callable接口的call方法
3.创建Callable接口的实现类对象
4.将此Callable接口作为参数传递给FutureTask类的构造器,创建FutureTask对象
5.将FutureTask对象传递给Thread构造器,创建Thread对象,并start线程
6.并可调用FutureTask类中的get方法获取实现类重写的call方法返回值返回值

要能说清各个类和对象的作用:
1.Callable接口
2.实现类,实现对象,call方法
3.FutureTask类,和FutureTask对象,get方法
4.Thread类,Thread对象,start方法

Callable与Runnable
1.Callable可以有返回值
2.Callable可以抛出异常,被外层捕捉
3.Callable支持泛型

线程池

corePoolSize:核心池大小
maximumPoolSize:最大线程数
keepAliveTime:线程没有任务多久会停止

步骤
1.创建指定线程数量的线程池:
ExecutorService service = Executors.newFixedThreadPool(10);

2.执行指定的线程操作,需要提供实现类Runnable接口或者Callable接口的实现类对象:
Service.execute(new 实现类()); 实现Runnable接口实现类
Service.submit(new 实现类()); 实现Callable接口实现类

3.关闭线程池:service.shutdown();

4.设置线程池属性:
4.1首先需要把ExecutorService对象强转为ThreadPoolExecutor对象,然后通过setXXXX()进行设置

String(不可变序列)

1.为final不可继承
2.实现了Serializable,表示字符串是支持序列化
实现了Comparable,表示可比较大小
3.定义了final char[] value用于存储字符串数据
4.String代表不可变的字符序列,不可变性(对字符串的任何修改都会重新创造对象)

当给字符串重新赋值时,需要重新制定内存区域
对现有字符串进行连接操作,也要重新指定内存区域
改变现有字符串,也要重新指定内存区域

5.字面量的给一个字符串赋值,此时字符串的值生命在字符串常量池
6.字符串常量池不会存储同内容的字符串

String str1 = “abc”;与String str2 = new String(“abc”);

请添加图片描述
1.str2类似于指针的指针,在堆中维护一个地址指向常量池。
2.String s = new String(“abc”);创建了两个对象,一个在堆中,另一个在char[]对于常量池中数据:“abc”;
3.类似String s2 = s1 + “abc”;凡事有变量参与的都类似于new,会先在堆中创建一个对象
4.引用凡是指向堆再指向常量池的字符串对象,使用intern方法,引用就直接指向字符串常量池
5.练习题:请添加图片描述
new出来的str是一个二级指针,而char型数组则是一级指针,
1.修改change中形参str的值,因为字符串的不可变性会让他重新指向一个字符串常量池对象;并不会对mian中的str有影响。
2.修改change中char型数组的值,应该是对地址指向的内容的修改,会修改实际内容
3.考察值传递和引用传递,形参;调用方法时因为传递的是两个对象会有两个形参,但 两个形参都是地址,但是字符串有不可变性

常用方法

1.int length();
2.char charAt(int index);
3.boolean isEmpty();
4.String toLowerCase();
5.String toUpperCase();
6.String trim();返回副本,忽略前后空白部分(空格)
7.boolean equals(Object obj);
8.boolean equalsIgnoreCase(String anotherString):忽略大小写的比较
9.String concat(String str); <=> +
10.int compareTo(String str); 比大小,返回差值
11.String substring(int beginIndex); 到末尾
12.Sring substring(int beginIndex, int endIndex);
13.boolean endsWith(String suffix);
14.boolean startsWith(String prefix);
15.boolean startsWith(String prefix, int toffset); 指定位置是否以指定前缀开始
16.boolean contains(CharSequence s); 是否包含char值序列
17.int indexOf(String str); 返回str第一次出现的索引,没有-1
18.int indexOf(String str, int fromIndex); 从指定索引开始搜
19.int lastIndexOf(String str);从后往前
20.int lastIndexOf(String str , int fromIndex);从后往前
21.String replace(char oldChar, char newChar);
22.String replace(CharSequence target, CharSequence replacement);
23.String replaceAll(String regex, String replacement); //正则
24.String replaceFirst(String regex, String replacement);//正则
25.boolean matches(String regex);//是否满足正则
26.String[] split(String regx);
27.String[] split(String regex, int limit);

string和基本数据类型
int
int num = Integer.parseInt(String str);
String str = String.valueOf(int num);
char数组
char[] charArray = str.toCharArray();
String str = new String(char[] arr);

StringBuffer(可变字符序列,线程安全)sychronized修饰方法

算法原理:
使用append()方法在字符串后面追加值的时候,如果长度超过了该字符串存储空间大小了就就会先进性扩容。构建新的并且存储空间更大的字符串,将旧的复制过去。
在进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容。

扩容规则:
先原始容量 * 2 + 2(加2是因为拼接字符串通常末尾都会有个多余的字符)
如果扩容了之后,容量够用,新的容量就为扩容之后的容量。
如果扩容了之后,容量不够用,新的容量就是所需要的容量,即原始字符串长度加上新添加的字符串长度。
扩容完成之后,将原始数组复制到新的容量中,然后将新的字符串添加进去。

StringBuilder(可变字符序列,线程不安全)

注解

代码里的特殊标记,这些标记可以在编译,类加载,运行时读取,并执行。通过注解,程序员可以在不改变原有逻辑的情况下,在源文件嵌入补充信息。
一. 文档注释
二.编译时进行格式检查:Override,Deprecated,SuppressWarning
三.跟踪代码依赖性,实现替代配置文件功能
四.自定义注解,注解声明为@interface

集合(Java容器)

Collection(接口)

请添加图片描述

单列数据,定义存取一组对象的方法集合
List:元素有序,可重复(ArrayList,LinkedList,Vector)
Set:元素无需,不可重复。(HashSet,LinkedHashSet,TreeSet)

源码分析

ArrayList

JDK7.0时,ArrayList list = new ArrayList();//底层创建了长度为10的Object[]数组
当容量不够,则扩容,默认扩为原来的1.5倍。同时将原数组中的数据复制到新的数组中。
开发者建议使用带参构造器 new ArrayList(int capacity);

JDK8.0中,ArrayList list = new ArrayList();//底层Object[] elementData初始化为{},在第一次调用add是,底层才创建长度为10的数组。

JDK7.0中ArrayList的对象的创建类似于单例的饿汉;而JDK8.0中的创建类似于懒汉式。

LinkedList

LinkedList list = new LinkedList(); //内部声明了Node类型的firt和last属性,默认值为null
list.add(123); //将123封装到Node中,创建了Node对象。

Vector

通过Vector()构造对象,饿汉式创建了长度为10的数组,扩容时扩大2倍。

Set(HashSet,LinkedHashSet,TreeSet)

向Set添加数据,一定要重写hashCode()和equals()方法,且两个方法要保持一致性,相等的对象有一样的散列码

HashSet:底层数组

LinkedHashSet:底层双向链表,内部声明Node对象,指向前后结点的Node,Node对象中声明元素elementData。

TreeSet:
自然排序中,两个对象相等的compareTo()返回0,不是equal
定制排序,相同返回0,不是equal

Collection常用方法

List:
add(Object obj)
remove(int index) / remove(Object obj)
set(int index, Object ele)
get(int index)
add(add int index, Object ele)
size()
遍历:Iterator迭代器,增强for,普通for

Map:

Map(接口)

请添加图片描述
有映射关系的数据(key-value)

Collections

Array是操作数组的工具类
Collections是操作Collection,Map的工具类
常用方法:
1.reverse
2.shuffle
3.sort
4.swap
6.max
7.min
8.ferquency

注解(Annotation)

Annotation可以像修饰符一样被使用,可以修饰包,类,构造器,方法,成员变量,参数,局部变量的声明。还可以添加一些参数值,这些信息被保存在Annotation的“name=value”中。
注解可以在类编译,运行时进行加载,体现不同的功能。

泛形

限制类型,防止类型错误,可能出现ClassCastException

I/O流

File类

  1. File类的一个对象,代表文件或者文件目录(文件夹)
  2. File类声明在java.io
  3. File类中关于文件或者文件目录的创建,删除,重命名。修改时间,文件大小等方法,并未设计到写入或者读取文件内容的操作,如果需要读取或写入文件的内容,必须使用IO流来完成
  4. 后续File类的对象常作为参数传递到流的构造器中,并指明读取或者写入的终点。

构造器:
File(String filepath)
File(String parentPaht, String childPath)
File(File parentFile, String childPath)

相对路径,绝对路径。
windows,dos 分隔符“"
UNIX,URL 分隔符"/"

流的三种分类

流向:输入输出
数据单位:字节流(非文本),字符流(char基本文本)
流的角色:节 点流,处理流

4个抽象基类,4个文件流(结点流),4个缓冲流(处理流的一种)

InputStream(字节流,输入) FileInputStream BufferedInputStream
OutputStream(字节流,输出)
Reader(字符流,输入)
Writer(字符流,输出) 请添加图片描述
访问文件为节点流,其余都为处理流(加速操作)

读取文件并输出

public class IOTest {
    @Test
    public void inputFileTest(){
        FileReader fr = null;          //保证fr的生存期:在try的大括号外有效,finally中可以关闭
        try{
            File file1 = new File("Hello.txt");// 1.实例化
            System.out.println("*********************");
            System.out.println(file1.getAbsoluteFile());
            fr = new FileReader(file1); //2.创建流
            int data;
            while((data = fr.read()) != -1) { //3.读取
                System.out.print((char)data);
            }
        }catch (IOException e){       //捕捉read操作异常 
            e.printStackTrace();
        }finally {
            try {
                if(fr != null) fr.close(); //4.关闭流
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
}

流操作流程

1.实例化File类对象: File file = new file(String);
2.提供具体的流: FileReader fr = new FileReader(file);
3.数据读入写出
4.关闭流: fr.close();

FileReader(read方法,字符流)

1.实例化File类对象: File file = new file(String);
2.提供具体的流: FileReader fr = new FileReader(file);
3.数据读入:
int data;
while((data = fr.read()) != -1) {Sout((char)data); }
使用while循环,没有数据返回-1退出循环
4.关闭流: fr.close();

说明点:
1.read(),返回输入字符,没有返回-1
2.为了保证留自由一定可以执行关闭,必须使用try-catch-finally
3.读入点文件一定要存在,不然会报FileNotFoundException

read();读入一个字符
read(char [] buffer);读入数组长度的字符到字符数组中

FileWriter(write方法,字符流)

1.输出操作,File不存在不会报错而会创建文件
2.根据构造器不同创建的不同的输出流对象:FileWriter(file,false)覆盖原文件;FileWriter(file,true)不会覆盖。

FileInputStream, FileOutputStream(字节流,也可以读写字符,但是不能在过程中查看,只能读写完后查看)

BufferedInputStream, BufferedOutputStream(提高读写速度)

1.实例化File类对象: File file = new file(String str);
2.提供具体的流: FileInputStream fis = new FileInputStream(File file);
3.提供具体的缓冲流:bis = new BufferedInputStream(FileInputStream fis);
4.缓冲流完成读写:bis.read(),bos.write();
5.关闭流,关闭外层流会自动关闭内层流:bis.close();bos.close();

    public void bufferTest(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try{
        	//1.实例化file对象
            File srcfile = new File("srcimage.jpg");
            File desfile = new File("desimage2.jpg");
            //2.实例化输入输出流
            fis = new FileInputStream(srcfile);
            fos = new FileOutputStream(desfile);
            //3.实例化缓冲流处理输入输出流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            
            //4.缓冲流完成读写
            byte[] buffer = new byte[10];
            int len;
            while((len = bis.read(buffer))!=-1) {
                bos.write(buffer,0,len);
            }
            
        }catch (IOException e){
            e.printStackTrace();
        }finally {
        	//5.关闭流,关闭外层流会自动关闭内层流
            try {
                if(bis != null) bis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(bos != null) bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

对象流(ObjectinputStream ObjectoutputStream)

对象序列化

允许把内存中的Java对象转换为平台无关的二进制流,从而允许把这种二进制持久的保存在磁盘上,或通过网络将二进制流传输到另一个网络结点,当其他程序获取这种二进制流,就可以恢复成Java对象。

可以将实现了Serializable接口的对象序列化为字节数据,时期在保存和传输时可被还原。

RMI(Remote Method Invoke-远程方法调用)过程的参数和返回值都必须实现机制,RMI是JavaEE的基础。

如果要让某个对象支持序列化,必须让对象所属的类和属性是可序列化的,则该类必须实习如下两个接口之一:1.Serializable;2.Externalizable

序列化

1.创建输出流:ObjectInputStream oos = new ObjectInputStream(“object.dat”);
2.输出对象: oos.write(new String"123456");
3.关闭流对象: oos.flush(); oos.close();

反序列化

1.创建输入流:ObjectOnputStream ois = new ObjectOnputStream(“object.dat”);
2.读入对象:Object obj = (String)ois.readObject(); //强转
3.关闭流对象: ois.close();

自定义可序列化接口:

1.需要实现Serializable接口(标志接口,没有方法需要重写)
2.为当前类提供全局常量: public static final long serialVersionUID = XXXXXXXL;

Java序列化是通过运行时判断类的serialVersionUID来验证版本是否一致(类可以修改,但是serialVersionUID要一致),反序列化时JVM会先把传来的字节流中的serialVersionUID和本地实体类的serialVersionUID进行比较,相同就认为一致,可以进行反序列化,否则就会抛出版本不一致的异常(InvalidCastException)

3.除了当前类需要实现Serializable接口,也要保证类的所有属性也是可序列化的
补充:不能序列化static和transient修饰的成员变量

NIO.2中Path,Paths,Files

Files为操控File对象的工具类
通过Paths类获取Path对象(Path替换File)请添加图片描述

网络编程

InetAddress对象代表IP

实例化
InetAddress inet = getByName(String host);
InetAddress inet = getLocalHost(); //127.0.0.1
常用方法
getHostName(); //获取域名
getHostAddress();//获取地址

Socket(端口号+IP)

InetAddrsss inet = new InetAddress(“127.0.0.1”);
Socket socket = new Socket(inet, 8899) //创建套接字,ip+port

TCP

客户端
1.创建Socket对象,指明服务器ip和port
2.获取输出流,输出数据
3.写出数据
4.关闭资源

服务端
1.创建服务器ServerSocket,指明自己的端口号 // Serversocket ss = new ServerSocket(8899);
2.调用accept()接收客户端socket
3.获取输入流
4.读入输入流中数据
5.关闭资源

UDP

URL

1.统一资源定位符
2.格式:http://localhost:8080/examples/image.jpg?username=shkstart&password=123
URL组成:协议://主机名/端口号/资源地址?参数列表
URL url = new URL(String str);

反射

请添加图片描述
运行时,不确定创造哪个对象,比如客户端有注册和登录两个功能,那么服务端就会有注册对象和登录对象,服务端无法在写代码的时候确定创建哪个对象,因此会需要反射根据需要创建对应的对象 。

Class类

理解java.lang.Class类
1.类的加载
程序在javac.exe之后,会生成字节码文件(.class),接着使用java.exe对某个字节码文件解释运行,相当于将字节码文件加载到内存中,此过程就称为类的加载。加载到内存中的类,我们称为运行时类,此运行时类,就作为Class的实例。
2.Class的实例对应一个运行时类
3.加载到内存中的运行时类,会缓存一定时间,我们可以通过不同的方式获取此运行时类。

获取Class实例方法

1.调用运行时类 的属性.class:
Class clazz = Person.class;

2.调用运行时类的对象,调用getClass():
Person p = new Person();
Class clazz = p.getClass();

3.调用Class的静态方法:forName(String classPath):
Class clazz = Class.forName(“com.atguigu.java.Person”);

4.类的加载器
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz = classLoader.loadClass(“com.atguigu.java.Person”);

类的加载过程

请添加图片描述
1.装载(Loading):class文件读入内存,并创建java.lang.Class对象。
2.链接(Linking):
1)验证:确保加载的类的规范性
2)准备:为类变量(static)分配内存并设置类变量默认初始值,在方法区进行分配
3)解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
3.初始化(Initialization):执行类构造器()方法

类的加载器

并不是继承关系,是一种层次关系,某层类加载器可以通过getParent()方法获得直接上层
请添加图片描述
分类(两种):
1.BootstrapClassLoader:引导类加载器,启动类加载器

使用C/C++语言编写,不能通过java代码获取实例
负责加载Java的核心库
如果使用其加载非核心类,类加载器会返回null,即加载失败

2.继承ClassLoader的类加载器:
1)ExtensionClassLoader:扩展类加载器
2)SystemClassLoader/ApplicaClassLoader:系统类加载器,应用程序类加载器

自定义类的默认加载器

3)用户自定义类的加载器(Tomcat)

实现应用的隔离,同一个类加载多个版本。(因为更新)
数据的加密:不让别人看类的定义方式。需要自定义的类加载器进行解密

反射的应用

创建运行时类的对象⭐️

1.通过Class的实例调用newInstance()方法
2.要求运行时类有空参构造器
3.空参构造器的权限要够

JavaBean为什么要提供一个公共的空参构造器?
1.子类构造器默认调用父类的空参构造器
2.在反射中,经常创建运行时类的对象,我们要求各个运行时类提供空参构造器(因为不同的类有不同类型的成员变量需要初始化),便于我们编写通用运行时类代码。

JDK9中通过Constructer类调用newInstance(…)

获取运行时类的内部结构

class clazz = Class.forName("全类名“);

(了解)获取运行时类的内部结构:所有属性,方法构造器。
getField
getMethod

(熟悉)获取运行时类的内部结构:
1.父类:Class superclass = clazz.getSuperclass();
2.接口: Class[] interfaces = clazz.getInterfaces();
3.包: Package pack = clazz.getPackage();
4.带泛形父类: Type superclass = clazz.getGenericSuperclass();
5.父类的泛形:

调用指定的结构:属性,方法,构造器⭐️

获取运行时类
Class clazz = Person.class;
获取运行时类的对象
Person per = (Person)clazz.newInstance();

调用指定属性步骤:
1.通过class实例调用getDeclaredField(String name),获取指定的属性名
Field nameField = clazz.getDeclaredField(“name”);
2.确保属性是可访问的
nameField.setAccessible(true);
3.通过Field类的实例调用get(Object obj)获取或set(Object obj,Object value)
nameField.set(pre, “Tom”);
或者类变量(静态变量)
infoField.set(null, “123”);可以不传入对象

调用指定的方法:
1.通过Class实例调用getDeclaredMethod(String methodName, Class…args);
Method showNationMethod = getDeclaredMethod(“showNation”, String.class, int.class);
String.class, int.class万物皆对象,代表形式参数为String类和int类
2.setAccessible(true)确保方法可访问
showNation.setAccessible(true);
3.通过Method实例调用invoke(Object obj, Object …objs),invoke()返回值即为Method对应方法的返回值。如果method返回void,invoke返回null。
Object return Value = showNationMethod.invoke(per, “CHN”, 10);

调用指定的构造器:

  1. Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
  2. constructor.setAccessible(true);
  3. Person per = (Person)consturctor.newInstance(“Tom”,12);

通过反射获取注解的信息

注解

自定义注解,以@SuppressWarning参照
元注解:对现有注解进行解释说明的注解,(注解的注解)
1.@Target:用于描述注解的适用范围,可以通过ElementType的10个常量对象指定
2.@Retention:描述注解的生命周期
SOURCE(源代码),CLASS(字节码),RUNTIME(运行时,唯有它能被反射读取)
3.@Documented:表面注解应该被javadoc工具记录
4.@Inherited:允许子类继承父类中的注解

新特性

请添加图片描述
1.语法规则(多关注)
2.增加,过时,删除API
3.底层优化

Lambda表达式

1.Lambda表达式使用举例:(o1,o2) -> Integer.compare(o1, o2);

2.Lambda表达式格式:
->: Lambda操作符
->左边:Lambda形参列表,对应着要重写的接口中的凑下方法的形参列表
->右边:Lambda体,对应着接口的实现类要重写的方法的方法体。

3.6种lambda表达式使用格式
(1)无参数,无返回值
Runnable r2 = () -> {
System.out.printlin("123);
};
(2) 一个参数,无返回值
Consumer con1 = (String s) -> {
System…;
}
(3)数据类型省略,可由编译器推断得到,类型推断(根据传入的数据推断)
Consumer con2 = (s) -> {
System.out.println(s);
};
(4)若Lambda只需一个参数可以省略参数括号
Consumer con2 = s -> {
System.out.println(s);
};
(5)Lambda需要两个以上参数,多条执行语句,并且有返回值
Comparator com2= (o1, o2) -> {
System…;
System…;
return o1.compareTo(o2);
};
(6) Lambda只有一条语句,return与大括号若有,都可以省略
Comparator com2 = (o1, o2) -> o1.compareTo(o2);

 4.Lamda表达式的本质:
 一方面:lambda表达式作为接口实现类的对象。
 另一方面:lambda表达式是一个匿名函数

5.函数式接口:
5.1什么是函数式接口?为什么需要函数式接口?
如果接口中只声明有一个抽象方法,则此类接口称为函数式接口
因为只有给函数式接口提供实现类的对象时,我们才可以用lambda表达式。
5.2 api函数式接口所在包
jdk8中声明在java.util.function中
5.3 四大核心函数式接口
请添加图片描述
6.lambda表达式语法规则总结
->的左边,lambda形参列表,参数的类型都可以省略。如果参数只有一个,则一对()也可以省略
->的右边:lambda体,对应着重写方法的方法提。如果方法体只有一条语句{}可以省略。如果有return关键字,则必须一起省略。

方法引用

1.举例
Integer::compare;

2.方法引用的理解
可以看作lambda表达式的进一步刻画
当需要提供一个函数式接口的实例,我们可以使用lambda表达式提供实例;当满足一定的条件的情况下,我们还可以使用方法引用或构造器引用替换lambda表达式。

3.方法引用的本质。
方法引用作为函数式接口的实例。

4.格式
类(或对象):: 方法名

5.具体使用情况说明:
情况1. 对象 :: 实例方法
Employee emp = new Employee(…);//Employee预先定义好getName方法(无参数,返回String)
抽象方法:
public interface Supplier {
T get(); //(抽象方法a:get() )
}
匿名实现
Supplier sup1 = new Supplier() {
public String get() {
return emp.getName(); //(方法b:getName())
}
};
要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的形参列表和返回值类型都相同。此时,可以考虑使用方法b实现对方法a的替换或覆盖,此替换或覆盖即方法引用。
注意:此方法b是非静态的方法,需要对象调用

情况2. 类 :: 静态方法
要求:函数式接口中的抽象方法a与其内部实现时调用的类的某个静态方法b的形参列表和返回值类型都相同。此时,可以考虑使用方法b实现对方法a的替换或覆盖,此替换或覆盖即方法引用。
注意:此方法b是静态的方法,需要类调用

情况3. 类 :: 实例 方法

要求:函数式接口中的抽象方法a与其内部实现时调用的对象的某个方法b的返回值类型都相同。同时抽象方法a中有n个参数,方法b有n-1个参数,且抽象方法a的第一个参数作为方法b的调用者,且抽象方法a的后n-1个参数与方法b的n-1哥参数的类型相同。则可以考虑使用方法b实现对方法a的替换。
此时,可以考虑使用方法b实现对方法a的替换或覆盖,此替换或覆盖即方法引用。
注意:此方法b是非静态的方法,需要对象调用。但形式上,写出对象a所属的类。

构造器引用

1.格式:
类名:: new;

2.说明:
调用类名对应类中某个确定构造器
具体调用类中的哪个构造器取决于函数式接口的抽象方法的形参列表。
<a,b,c> c为返回值类型,a,b为参数。
3.数字引用
格式:数组名[] :: new;

Stream API

1.Stream API vs集合框架:
Stream API关注多个数据的计算(排序,查找,过滤,映射,遍历),面向CPU。
集合关注数据的存储,面向内存。
Stream API之于集合,类似于SQL之于数据表的查询。

  1. 使用说明
    (1)Stream 不会存储元素
    (2)Stream 不会改变源对象。相反,会返回一个持有结果的新Stream
    (3)Stream 操作是延迟执行。他们等到需要结果才执行,
    (4)Stream一旦执行终止操作,就不能调用其他中间操作或者终止操作。

3.Stream执行流程
(1)Stream实例化
(2)一系列中间操作
(3)执行终止操作。

语法新特性

1.jshell
2.try-catch资源关闭:

//jdk8
try{
}catch(){
}finally{
}
//jdk7
try(创建需要关闭的资源){
//执行操作
}catch(){
}
//jdk9
//try之前创建资源
InputStreamReader reader = new InputStreamReader(System.in);
OutputStreamWriter writer = new OutputStreamWriter(system.out);
try(reader;writer) {
//reader,writer不可再赋值;
}catch(){
}

3.局部变量类型推断:var关键字。

1.局部变量实例化:var list = new ArrayList();
2.增强for循环:for(var v :list){}
3.传统for循环: for(var i = 0; i < 100; i++){}
4.返回值类型含复杂泛形结构
4.instanceof模式匹配

  1. switch

->操作符,可以不再使用break,
形如:case Monday -> System.out.println(“Monday”);
switch结构可以返回数值,使用yield终止方法, yield 1;(返回1并终止switch方法)
6.文本块的使用:“”“文本内容”“”(三个双引号包围文本内容)
7.record引用类型:预先提供许多方法:构造器,访问方法,toString方法等。
8.密封类:密封类只能被指定的子类继承,sealed关键字

public sealed class Person permits Student, Teacher, Worker{
}
//要求指定的子类必须是final,sealed,non-sealed
final class Student extends Person{} //Student类不能再被挤出
sealed class Teacher extends Person permits SeniorTeacher{}//  Teacher类只能被指定的子类继承
non-sealed class Worker extends Person{}//Worker类被继承时没有限制

Optional类

1.目的和原理:为解决空指针异常,引入Optional类。通过检查空值的方式避免空指针异常。
Optional类是容器类,可以保存类型T的值,代表值存在。或者保存null,表示值不存在。如果存在,则isPresent()方法返回true,低矮用get()方法返回该对象。

2.实例化

String star = "迪丽热巴";
//1.实例化
//ofNullable(T value):创建Optional实例,value可能是空也可能非空
Optional<String> optional = Optional.ofNullable(star);
//orElse(T other):如果optional内value为null则返回传入的值,否则返回optional内value的值
String otherstar= "杨幂";
String finalstar = optional.orElse(otherstar);
//get方法获取value
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值