Java学习技术总结_Java基础学习下

异常

  1. 出现异常终止
  2. 出现异常继续运行
  • 分类
    异常是类,所有异常类的根类是Throwable

    • Err
      • 异常不需处理(不需要写throws抛出或者try/catch),因为不需要写处理异常所以会自动打印栈的跟踪信息
    • Exception
      • 异常需要处理(需要抛出)
  • 编译期异常,try,catch是必不可少的,finally可以不写;如未调用含有异常方法,则可以用try,final组成

  • 运行期异常继承RuntimeException,不用try/catch或添加throws

  • throws将异常抛出,交给调用者

自定义异常

  • 继承Exception或者RuntimeException

    • 添加构造方法

    • 在需要报异常的地方生成异常,若是运行期异常需要在调用该异常方法的地方用try/catch捕获

      没有向外抛出异常,在调用自定义异常时,就解决了异常

         try {
                  throw new MyProductException("出错了");
              } catch (MyProductException e) {
                  System.err.println(e.getMessage());
              }
      

集合

就是数据结构,包含List,Set,Map

  • List(存的都是地址**,list对象被引用后无法垃圾回收**)

    List就是列表,用来存储一组数据的数据结构

    可变长的数据结构,可以知道里面存了多少数据

    List是一个有序的列表,数据可以重复

    List可以保存不同类型的数据

    ArrayList

    ArrayList采用数组方式实现,因为是采用数组实现,所以对元素插入和删除会较慢

    读写(不超过默认长度)和遍历都很快,插入和删除数据比较慢

    LinkedList

    采用双向链表实现,插入,修改,删除速度特别快,查询和遍历速度慢

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RymZzKzB-1660484425169)(C:\Users\24890\Desktop\上课\笔记\Java高级\第十一天\Java学习第十一天_高级第一天.assets\双向链表结构.jpg)]

    • 插入和删除速度快
    • 查询和遍历速度慢
    • 链表的保存的数据是地址
    • 每个子节点除了自身的数据地址外,还保存前一个和后一个的节点地址
      • pop,对于栈,弹出
      • push,对于栈,压栈

泛型

因为List可以存各种类型的数据,但是取出的是Object类型数据,需要强制转换

泛型可以解决这个问题,在创建List时,可以指定存储的类型

泛型不能是基本类型

Set

  • 无序集合
  • 元素不重复(覆盖)
  • 没有索引(序号),不能通过下标访问

HashSet->LinkedHashSet

TreeSet

哈希表 hash table

  • 哈希表,散列表,是一种高效数据结构

  • 要保存的数据称为值,根据hash算法给每一个值算出一个hash code

  • 保存数据就用hash code根值一一对应

hash table保存数据的原理

  • 根据hash code从表里面查找是否存在:

    • 不存在,直接添加
    • 存在,再判断equals是否相等:
      • false,直接添加
      • true,说明两个值一样,不添加

    Hash Code:

    • 两个对象的HashCode值相同,它们的equals不一定相同
    • 两个值得equals值相同,HashCode的值也不一定相同
    • 两个值得HashCode相同,equals相同,这个两个值相同

HashSet

采用hash表实现

元素不重复

允许null但不能重复)

TreeSet

  • ​ 二叉树

    每个节点只有两个分支

  • 满二叉树

    除了叶节点外,每个分支都有两个节点

  • 完全二叉树

    最底层可以不满,但必须保证左边填满

  • 二叉查找树

    排列顺序,每个节点分支,左节点比父节点小,右节点比父节点大

  • 平衡二叉树

    左右子树高度差小于1,并且子树也是平衡二叉树

  • 红黑树

    自平衡的二叉查找树

    1. 节点只有红,黑色
    2. 根节点是黑色
    3. 叶节点为黑色,叶节点不存数据,为NIL标志
    4. 一个节点为红,则它的两个子节点必须为黑色(从根节点到叶子节点使用路径,不可能存在两个连续的红色节点)
    5. 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点

TreeSet采用红黑树数据结构来实现

  • 不能添加null

  • 不能添加重复的元素

  • 添加的元素会被排序(大小排序),遍历出来是按顺序排列的

  • TreeSet的元素必须实现Comparable

    自定义的对象需要实现Comparable接口,重写compareTo方法

    • 当前对象大于参数对象返回1,TreeSet的内部为 升序

    • 当前对象大于参数对象返回-1,TreeSet的内部为 降序

    • 如果不实现Comparable接口,会报一个类型转换异常

    • 当判断相等时,TreeSet不会存入,如果要存入需要把等于条件去掉

public class Sportsman implements Comparable<Sportsman> {
    private String name;
    private float score;
    ...
    @Override
    public int compareTo(Sportsman o) {
        if (this.score>o.score){
            return -1;
        }else if(this.score<o.score){
            return 1;
        }else{
            return 0;
        }
    }
}

Collection集合用迭代器遍历(Iterator)

调用list的iterator()方法返回一个泛型迭代器<T>对象,结合对象hasNext()方法判断迭代器是否为空,以及next()取出元素进行迭代

//iterator迭代器,迭代器里面存数据
Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()) {//判断里面是否还有数据
            Integer next = iterator.next();//从迭代器里面取出一个数据,取一个少一个
            System.out.println(next);
        }

只要实现了Iterable接口就可以使用Itertor迭代器

Collections集合工具类

  • Collections与Collection区别
  • Collection是接口,是List和Set的父接口
  • Collections是处理集合的工具类
package Java高级.第十二天;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CollcetionsDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(11);
        list.add(22);
        list.add(33);
        list.add(99);
        list.add(22);
        list.add(66);
        list.add(70);
        Collections.shuffle(list);//随机打乱list的顺序
        System.out.println(list);
        Collections.reverse(list);//逆序
        System.out.println(list);
        Collections.sort(list);//调用sort方法必须泛型必须实现Comperable接口,并重写接口里的方法
        System.out.println(list);
        Collections.swap(list,0,3);
        System.out.println(list);
        System.out.println(Collections.max(list));//返回集合中最大元素
        System.out.println(Collections.min(list));//返回集合中最小元素
    }

}

  • Collections.shuffle 随机打乱list的顺序
  • Collections.reverse 逆序
  • Collections.sort 调用sort方法因为是泛型,必须实现Comperable接口,并重写接口里的方法

Map

  • 保存键值对数据(key-value)
  • key不能重复,value可以重复
  • key和value都可以为null

HashMap

采用数组+链表+红黑树的数据结构来实现

  • 先根据hash code保存数组中,如果出现hash碰撞,用链表,链表长度超过8,改用红黑树
public class HashMapDemo {
    public static void main(String[] args) {
        //默认长度16 加载因子0.75
        HashMap<String, String> map = new HashMap<>();
        map.put("yyds", "永远单身");
        map.put("emo", "抑郁了");
        map.put("u1s1", "有一说一");
        System.out.println(map.get("yyds"));//根据key查询对象value
        System.out.println(map);
        System.out.println(map.containsKey("emo"));//查询Key是否包含
        System.out.println(map.containsValue("蔡徐坤"));//查询Value是否包含
        System.out.println(map.size());//获取键值对个数
        map.remove("yyds");//删除
        map.clear();//格式化
        System.out.println(map.isEmpty());

        map.put("yyds", "永远单身");
        map.put("emo", "抑郁了");
        map.put("u1s1", "有一说一");
        /**
         *变量value
         */
        for (String s :
                map.values()) {
            System.out.println(s);
        }
        /**
         *变量key
         */
        for (String s :
                map.keySet()) {
            System.out.println(s);
        }
        System.out.println("==========遍历entry============");
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String,String> entry:
             entries) {
            System.out.println(entry.getKey()+","+entry.getValue());
        }
    }


}

集合继承关系

在这里插入图片描述

注意

Set和Map默认长度16,都存在加载因子为0.75,当使用长度为75%时,自动准备加载集合长度,并非使用完全时再加载长度

IO文件读写

Input输入,Output输出

信息需要永久保存(持久化),一般用文件的形式把信息保存到磁盘上

程序运行需要一些基本配置信息,配置信息也是保存在磁盘文件中

程序从磁盘读取文件,就称为Input,把文件写到磁盘,称为Output.已内存为参考

java.io包下的分类

按照输入输出的方向分类:

  • 输入 Input,Reader
  • 输出 Output,Writer

按照数据格式:

  • 字节流(二进制文件,如:exe,office,图片,视频,音频)

    Stream

  • 字符流(文本文件,txt,程序源代码,html)

    Reader,Writer

文件

所有的IO操作都于文件类对象打交道

File类方法总结:

file.exists()//判断该对象 文件或目录是否存在
file.isFile()//判断该对象 是否是文件
file.isDirectory()//判断该对象 是否是目录
file.lastModified()//最后一次的文件修改时间
file.length()//返回文件长度,以字节byte为单位
file.listFiles()//将file内子文件和目录以File对象存入数组,如果file内为null,则产生的数组长度为0

序列化

Java在运行时,如果需要保存对象的状态(下次在运行时,也能还原当前对象状态),就需要使用序列化操作

注意:当某些变量不想被序列化,同是又不适合使用static关键字声明,那么此时就需要用transient关键字来声明该变量。

IO编程:存储对象

网络编程:如果想把一个对象从一台机器(虚拟机)发送到另一台机器(虚拟机),这种情况需要把对象序列化二进制内容,然后再网络发送,对方收到二进制内容,再反序列化为对象

ObjectOutPutStream序列化

把对象保存在文件中,要被序列化的对象需要实现Serializable接口

  • Student类,实现Serializable

    import java.io.Serializable;
    
    public class Student implements Serializable {
        //eclipse中需要生成序列化版本
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    

    运行

    package Java高级.第十四天.序列化;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    
    public class SerializableDemo {
        public static void main(String[] args) {
            Student student = new Student("蔡徐坤",18);
            ObjectOutputStream oos=null;
    
            try {
                oos= new ObjectOutputStream(new FileOutputStream("src\\Java高级\\第十四天\\序列化"));
                oos.writeObject(student);
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally{
                try {
                    if (oos!=null){
                        oos.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
    
        }
    }
    
    

    反序列化

    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    
    public class SerializableInputDemo {
    
        public static void main(String[] args) {
            ObjectInputStream ois = null;
            try {
                 ois= new ObjectInputStream(new FileInputStream("src\\Java高级\\第十四天\\序列化/蔡徐坤.data"));
                try {
                    Student s =(Student) ois.readObject();
                    System.out.println(s);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (ois!=null){
                    try {
                        ois.close() ;
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
    

    序列化与反序列化不能更改序列化类,否则反序列化会失败

    序列化应用于:上传图片,Excel(POI EasyExcel),生成文件

常量池中存的是一种对象吗

常量池中存的也是一种对象,主要针对String类型,如果用字面量赋值的string,就会在常量池中创建一个对象,下一次再用相同的
基本类型:指向的是数值并不是指向堆中的对象

如果进行引用,虚拟机不能自动垃圾回收吗

首先对Java虚拟机的内存进行配置:
在这里插入图片描述

List集合泛型为引用类型的对象如果被引用后没有清除掉,直接将List的对象赋null空值会发生三种情况:

  1. 不能自动垃圾回收
  2. JVM虚拟机内存泄漏
  3. 如果次数多,JVM虚拟机内存耗光,会产生内存溢出

抽象abstract

抽象可以修饰类,方法
抽象方法,就是没有方法体,目的是同一方法名,具体实现交给子类,一般来说每个子类实现都不一样

网络编程

  • TCP/IP

    长连接,连接后一直保持连接,可靠通讯,一字节流传输,效率低

  • UDP

    非长连接,通讯不可靠,数据报文发送,效率高

  • 端口 prot

    区分同一台服务器不同的网络通讯软件

    操作系统也会用到端口号,操作系统保留1024以下的端口,要避开,一些软件的端口也要避免:tomcat 8080 数据库 3306 oracle 1512 如果自己的程序与其他软件用来同样端口,同时启动时其中一个会端口占用

InetAddress类(网络地址类)

用来表示网络上的一台服务器,网络通讯中数据的来源或目的地,相当于文件读写里的File类

  • InetAddress.getLocalHost();//获取本地网络地址对象,如果主机存在多个ip,返回最靠前的ip
    
  • InetAddress.getLocalHost().getAddress();//获取数组类型的ip地址,有符号
    
  • InterAddress.getByName(“www.baidu.com”);获取服务器地址对象

  • getHostAddres();返回ip地址

  • getHostName;返回域名或机器名

    import com.sun.jmx.snmp.InetAddressAcl;
    
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    import java.util.Arrays;
    
    public class InetAddressDeomo {
        public static void main(String[] args) {
            //本机地址:localhost或127.0.0.1
            try {
                InetAddress localHost = InetAddress.getLocalHost();//获取本地的Localhost
    //            System.out.println(new String(localHost.getAddress()));//未知
                System.out.println(localHost.getHostAddress());//ip地址
                System.out.println(localHost.getHostName());//计算机名称
                InetAddress byName = InetAddress.getByName("192.168.3.120");
                System.out.println("====================");
                System.out.println(byName.getHostAddress());
                System.out.println(byName.getHostName());
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }finally{
    
            }
        }
    }
    
    

ServerSocket类

TCP通讯(Socket 套接字)的服务器端,被动等待客服端建立连接,获取连接后的Socket

  • 创建ServerSocket(服务器套接字)
  • 调用accept方法等待客服端建立连接,获取连接后的Socket

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SeverSocketDemo {
    public static void main(String[] args) {
        ServerSocket ss = null;
        Socket accept = null;
        InputStream inputStream = null;
        try {
            InetAddress byName = InetAddress.getByName("192.168.3.56");//创建网络对象
            ss = new ServerSocket(10086,9, byName);//服务器Socket,端口,连接数,网络地址
            accept = ss.accept();//接收,对待客户端的Socket,程序被阻塞
            inputStream = accept.getInputStream();
            byte[] bytes=new byte[1024];
            int count=inputStream.read(bytes);
            System.out.println(new String(bytes,0,count));
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
                accept.close();
                ss.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

Socket 类

套接字的客户端,去连接服务器端,连上之后发送信息

  • 创建客户端套接字Socket,ip和端口跟服务器端设置一样
  • 得到输出流
  • 往输出流写信息
package com.hqyj;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class SocketDemo {
    public static void main(String[] args) {
        Socket socket = null;
        OutputStream outputStream = null;
        try {
            socket = new Socket("192.168.3.178", 9090);
            outputStream = socket.getOutputStream();
            byte[] bytes = "您好!".getBytes();
            outputStream.write(bytes);
            outputStream.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(outputStream != null){
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket != null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

UDP

  • DatagramSocket 创建UDB连接
  • DatagramPacket 报文内容

服务端代码

import java.io.IOException;
import java.net.*;

public class UdpServer {
    public static void main(String[] args) throws IOException {
        //创建Socket
        DatagramSocket socket = new DatagramSocket(8888, InetAddress.getByName("192.168.3.178"));

        //创建packet对象
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);

        while (true){
            //读取数据
            socket.receive(packet);
            //返回读取到的字节数
            int length = packet.getLength();
            //new String(bytes, 0, length) 只打印有内容的字节,避免打出空白内容
            System.out.println(new String(bytes, 0, length));
        }

    }
}

客户端代码

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpClient {
    public static void main(String[] args) throws IOException {
        //创建socket
        DatagramSocket socket = new DatagramSocket();

        //控制台输入内容,完成发送
        Scanner scanner = new Scanner(System.in);
        while (true){
            System.out.println("请输入要发送的消息:");
            String msg = scanner.next();
            byte[] bytes = msg.getBytes();
            //创建报文包,参数依次为:字节数组, 长度,服务器地址, 服务器端口
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.3.178"), 8888);
            //发送报文包
            socket.send(packet);
        }
    }
}

多线程

进程和线程

  • 进程process

    每个程序运行就会创建一进程,进程就是由操作系统管理,每个进程独享一段内存空间,进程之间互不干扰

  • 线程Thread

    线程是进程的组成单元,一个进程可以创建多个线程,多个线程之间共享同一资源

    Java中,运行的进程有一种看不见的垃圾回收器线程在运行

并行和并发

  • 并行

    多个线程同时都在运行,并行

  • 并发

    并行的多个线程同一时间点访问同一资源(执行同一方法或访问同一属性),产生并发可能导致数据不一致(混乱)

    多线程好处:加快程序运行速度,防止程序阻塞

    多线程坏处:产生并发线程

同步和异步

  • 同步(线程安全):StringBffer,ConcurrentHashMap

    多个线程排队执行,称为同步,同一时间点只有一个线程在执行,不会导致并发,执行效率不高(兼顾效率,只会对造成数据不一致的代码同步)

  • 异步(线程不安全),StringBuilder,HashMap

    多个线程同时运行,可能会导致并发,执行效率比较高

创建和执行线程

方式一,继承Thread

  • 继承Thread类

  • 调用线程类的start()方法启动线程,并不一定会立即执行,什么时候执行这个线程是由进程调度的,start()方法相当于告诉进程,这个线程准备好了,不能直接调用run方法,是没有多线程的效果

    Thread线程类

    
    public class Thread1 extends Thread{
        public Thread1(String name) {//构造方法不能重写,只能生成一个调用父类的构造方法
            super(name);
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 20; i++) {
                System.out.println(getName()+""+i);//this可以不要,因为是Thread的方法
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

    测试代码

    public class Thread1Test {
        public static void main(String[] args) {
            Thread1 thread1 = new Thread1("线程一");
            Thread1 thread2 = new Thread1("线程二");
            thread1.start();//run方法是可以运行的,运行没有多线程效果,因为线程是由进程控制的,而线程是否执行却是由操作系统决定,是不可控制的
            thread2.start();
        }
    }
    
    

    第二种方式,实现Runnable接口

    • 实现Runnabel接口,并在run方法写入线程代码
    • 创建一Thread对象,构造方法参数是实现了Runnabel接口类的对象
    • 调用Thread对象的start方法启动线程

    Runnabel代码

    public class Thread2 implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                //Thread.currentThread()获取当前线程对象
                System.out.println(Thread.currentThread().getName()+ i);
            }
        }
    }
    
    

    测试代码

    public class Thread2Test {
        public static void main(String[] args) {
            Thread2 t1 = new Thread2();
            Thread2 t2=new Thread2();
            new Thread(t1).start();
            new Thread(t2).start();
        }
    }
    
    

    方式三,实现Callable接口

    FutureTask实体类实现了RunnableFuture接口,RunnableFuture接口继承了Future,Runnable接口,因为继承了Runnable接口,所以可以作为Thread的参数对象,FutureTask的构造参数需要Callable的实体类对象,Callable是顶级接口

    • 实现Callable接口,call方法内写入线程代码
    • 创建FutureTask对象,构造方法是实现了Callabel接口对象
    • 创建Thread对象,构造方法的参数是FutureTask对象
    • 调用start方法启动线程

    Callable代码

    import java.util.concurrent.Callable;
    
    public class Thread3 implements Callable<String> {
    
        @Override
        public String call() throws Exception {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
            return Thread.currentThread().getName();
        }
    }
    
    

    测试代码

    
    import java.util.concurrent.FutureTask;
    
    public class Thread3Test {
        public static void main(String[] args) {
            Thread3 callable1 = new Thread3();
            Thread3 callable2 = new Thread3();
            FutureTask<String> stringFutureTask1 = new FutureTask<>(callable1);
            FutureTask<String> stringFutureTask2 = new FutureTask<>(callable2);
            new Thread(stringFutureTask1).start();
            new Thread(stringFutureTask2).start();
    
        }
    }
    
    

线程生命周期

在这里插入图片描述
new 新生态
新生状态,当线程被实例化后new Thread,就进入新生状态

Runnable就绪态
就绪状态,当线程对象执行了start()后进入就绪状态
就绪状态的线程可以执行,但不会执行,等待线程调度触发他执行

Running 运行状态
当线程被激活执行,这个时候就是运行状态,执行run()方法,一个执行周期内不一定能执行完整个run方法,如果分配CPU时间片被消耗完毕或线程调用yield()方法,线程会退回就绪状态,等待下次分配CPU时间片进入运行态,如果run方法被执行完毕就会进入终止态,且不可逆

Blocked 阻塞态
暂停运行,正在运行的线程执行了sleep(),wait()方法,就进入阻塞状态,因sleep()方法阻塞的线程,sleep时间到了后,重新返回就绪状态,因wait()方法阻塞的线程,必须等待notify或notifyAl被执行,才能由阻塞态重新回到就绪态

Terminated 结束态
终止状态,run()正常执行完毕,就进入终止状态,线程生命周期到此结束

线程不安全(并发)

解决线程不安全问题

加锁

把并发代码(或方法)添加一个同步的synchronized关键字给这段代码加锁(让这段代码变为同步的代码),小括号里面的就是加锁对象,如果有对象就用这个对象,没有可以new 一个Object对象

死锁

两个线程相互等待对方释放它额锁定资源,两个线程都没有办法执行,程序将会一直处于等待状态,不会结束,也不会成功运行,这种现象就是死锁

形成条件

  • 互斥使用,当一个资源被一个线程使用时,另一个线程不能使用
  • 不可抢占,资源请求者不能强制从资源占用者手中夺取资源,只能由资源的占有者主动释放
  • 请求和保持,当资源的请求者在请求已占用的资源,该资源一直不被释放
  • 循环等待,A线程持有资源1等待资源2,B线程持有资源2等待资源1

避免死锁

  • 以相同顺序去锁定资源
  • 另外建立一个锁对象,只锁一个对象,不要锁多个对象

JDK1.8新特性

接口默认方法

  • default

    • 接口可以有实现的方法,加上default(并非缺省)关键字
    • 一个接口里可以有多个default修饰的方法
    • 该方法必须实现,不能只声明
    • 加了default关键字的方法必须实例接口并实现才可以调用
  • static

    • 接口可以有实现的方法,加上static关键字
    • 一个接口里可以有多个static修饰的方法
    • 该方法必须实现,不能只声明
    • 加了static关键字的方法通过接口调用该方法

函数式接口

  • 只有一个抽象方法,可以有多个实现方法

  • 函数式接口一般在接口名称上添加注解:@FunctionalInterface,注解和函数式接口没有必然关系,加了注解强转语法检查是否只有一个抽象方法,只要满足只有一个接口方法,不叫注解@FunctionalInterface它也是函数式接口,注解的目的只是更能保障它是一个函数式接口
    
  • 作用:函数式接口在实现的时候可以用Lambda表达式(箭头函数),还可以用new的接口方式

注解

注解是一个接口,定义时和接口类似用@interface加一个@

Lambda表达式

//Lambda参数不需要写类型
    //表达式只有一行代码,不用写大括号,分号
    //() -> 5//无参方法,不用写分号,只有一行代码,自动作为返回值,没有参数,参数需要写小括号
    //x-> 2*x//一个参数不用写小括号
    //(x,y) ->x-y
    //()->{多行代码}//方法体有多行代码需要加大括号,分号

JDK的类中,只要某个方法的类型是函数式接口,调用该方法的时候就可以用Lambda表达式

Stream

集合类型类都有stream方法,产生一个数据流,可以对数据流做处理:forEach,map,filter,limt,sorted,Collectors

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

public class StreamDemo {
    public static void main(String[] args) {
        //filter 过滤
        List<String> stringList = Arrays.asList("dasd", "dasdas", "dasdsa", "", "dasdqe");
        List<String> collect = stringList.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList());
        System.out.println(collect);
        //将集合转换成Stream流调用filter过滤,参数可以是Lambda代码,再调用collect进行收集,参数是Collectors是收集后的对象toList()转换成需要的类型
        //map 映射
        List<Integer> integerList = Arrays.asList(1, 2, 3, 6, 4, 5);
        List<Integer> collect1 = integerList.stream().map(inem -> inem * inem).collect(Collectors.toList());
        System.out.println(collect1);
        //limit 限制数量
        Random random = new Random();
        random.ints().limit(2).forEach(itrm -> System.out.println(itrm));
        //sorted 排序
        List<Integer> integerList1 = Arrays.asList(9, 65, 66, 5645, 223, 12, 545, 65, 78, 22, 1, 54, 6, 6, 3, 5);
        integerList1.stream().sorted().forEach(item -> System.out.println(item));
        //collect 将数据流拼接成字符串
        String collect2 = stringList.stream().collect(Collectors.joining("蔡徐坤"));
        System.out.println(collect2);
    }

}

方法引用

对象::方法

//用小括号里面指定的方法来处理foreach出来的的每个元素
        integerList1.forEach(System.out::println);

Optional

为了解决放回值为unll的一个类

        //Optional为了解决返回值为null
        //sum1(null,3).intValue();抛出空指针异常
        if (sum2(null,3).isPresent()){//是否有值
            System.out.println(sum2(null,3).get().intValue());
        }else{
            System.out.println("无");
        }

    private  static Integer sum1(Integer a,Integer b){
      if (a==null||b==null){
          return null;
      }else

        return a+b;
    }


    private  static Optional<Integer> sum2(Integer a, Integer b){
        if (a==null||b==null){
            return Optional.empty();//empty方法没有给Optional赋值
        }else

            return Optional.of(a+b);//把值封装到Optional里,使用的时候用get()方法取值
    }

日期时间类

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class LocalDateDemo {
    public static void main(String[] args) {
        LocalDateTime now=LocalDateTime.now();//创建当前时间的日期时间对象
        System.out.println(now);
        LocalDate localDate = now.toLocalDate();//只要日期的对象
        System.out.println(localDate);
        LocalTime localTime = now.toLocalTime();//只要时间的对象
        System.out.println(localTime);
        System.out.println(now.getMonthValue());//返回月份
        System.out.println(now.getYear());//一年的第几天
        System.out.println(now.getDayOfMonth());//每个月的第几天,就是号数
        System.out.println(now.getDayOfWeek());//返回星期对象
        System.out.println(now.getDayOfWeek().getValue());//返回数字星期
        System.out.println(now.getHour());//返回当前小时(几点,24小时制)
        System.out.println(now.getMonth());//返回分钟
        System.out.println(now.getSecond());//返回秒
        now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));//格式化日期
        System.out.println(now.plusDays(40));//加天也可以加时分秒年

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值