线程安全的类—方法加入了synchronized关键字

  • StringBuffer
  • Vector(不常用) —- synchronizedList
  • Hashtable(不常用) —- synchronizedMap

    1. ------ synchronizedSet

    线程不安全的类

  • StringBuilder

  • ArrayList
  • HashMap ```java

    1. new StringBuffer();
    2. new StringBuilder();
    3. new Hashtable<>();
    4. new HashMap<>();
    5. new Vector<>();
    6. new ArrayList<>();
    7. List<Integer> list = Collections.synchronizedList(new ArrayList<>());
    8. Map<Integer,String> map = Collections.synchronizedMap(new HashMap<>());
    9. Set<Integer> set = Collections.synchronizedSet(new HashSet<>());
  1. <a name="ovsgy"></a>
  2. ### Lock锁
  3. ```java
  4. public class MyThread implements Runnable {
  5. private int tickets = 100; //总票数
  6. private Lock lock = new ReentrantLock();
  7. public MyThread() {
  8. }
  9. @Override
  10. public void run() {
  11. while (true) {
  12. //解决线程同步安全问题
  13. try {
  14. lock.lock(); //加锁
  15. if (tickets > 0) {
  16. try {
  17. Thread.sleep(100);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets-- + "张票");
  22. }
  23. } finally {
  24. lock.unlock();//释放锁
  25. }
  26. }
  27. }
  28. }

生产者消费者模式

image.png

  1. public class Customer implements Runnable{
  2. private Box b;
  3. public Customer(Box b) {
  4. this.b = b;
  5. }
  6. @Override
  7. public void run() {
  8. while (true){
  9. b.get();
  10. }
  11. }
  12. }
  1. public class Producer implements Runnable {
  2. private Box b;
  3. public Producer(Box b) {
  4. this.b = b;
  5. }
  6. @Override
  7. public void run() {
  8. int i = 1;
  9. while (i<6){
  10. b.put(i++);
  11. }
  12. }
  13. }
  1. public class Box {
  2. private int milk;
  3. private boolean state = false; //默认状态-->表示奶箱中没有奶
  4. public synchronized void put(int milk){
  5. if (state){
  6. try {
  7. wait();
  8. } catch (InterruptedException e) {
  9. e.printStackTrace();
  10. }
  11. }
  12. this.milk = milk;
  13. System.out.println("送来了第"+this.milk+"瓶奶");
  14. //修改状态
  15. state = true;
  16. //唤醒其他等待线程
  17. notifyAll();
  18. }
  19. public synchronized void get(){
  20. if (!state){
  21. try {
  22. wait();
  23. } catch (InterruptedException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. System.out.println("消费者消费了第"+this.milk+"瓶奶");
  28. state = false;
  29. notifyAll();
  30. }
  31. }
  1. public class Demo {
  2. public static void main(String[] args) {
  3. Box b = new Box();
  4. Producer p = new Producer(b);
  5. Customer c = new Customer(b);
  6. Thread t1 = new Thread(p);
  7. Thread t2 = new Thread(c);
  8. t1.start();
  9. t2.start();
  10. }
  11. }

送来了第1瓶奶 消费者消费了第1瓶奶 送来了第2瓶奶 消费者消费了第2瓶奶 送来了第3瓶奶 消费者消费了第3瓶奶 送来了第4瓶奶 消费者消费了第4瓶奶 送来了第5瓶奶 消费者消费了第5瓶奶

网络编程

  1. public static void main(String[] args) throws UnknownHostException {
  2. //获取ip地址与主机名
  3. InetAddress address = InetAddress.getByName("117.154.105.233");
  4. String name = address.getHostName();
  5. String ip = address.getHostAddress();
  6. System.out.println(name);
  7. System.out.println(ip);
  8. }

UDP协议

优点:消耗少
缺点:不太可靠,数据可能会丢失
image.png

  1. public static void main(String[] args) throws IOException {
  2. DatagramSocket ds = new DatagramSocket();
  3. byte[] bys = "Hello UDP协议".getBytes();
  4. int len = bys.length;
  5. InetAddress address = InetAddress.getByName("117.154.105.233");
  6. int port = 10086;
  7. //创建数据包
  8. DatagramPacket dp = new DatagramPacket(bys, len, address, port);
  9. //发送数据
  10. ds.send(dp);
  11. //关闭
  12. ds.close();
  13. }

image.png

  1. public static void main(String[] args) throws IOException {
  2. //接收数据
  3. DatagramSocket ds = new DatagramSocket(10086);
  4. byte[] bys = new byte[1024];
  5. int len = bys.length;
  6. //创建数据包
  7. DatagramPacket dp = new DatagramPacket(bys, len);
  8. ds.receive(dp);
  9. //解析数据包
  10. byte[] datas = dp.getData();
  11. int lenth = dp.getLength();
  12. String dataString = new String(datas,0,lenth);
  13. System.out.println(dataString);
  14. //关闭
  15. ds.close();
  16. }

TCP协议

三次握手
可以保证数据传输的安全

聊天示列

发送用户端
输入886结束退出
可多开SendDemo窗口

  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStreamReader;
  4. import java.net.DatagramPacket;
  5. import java.net.DatagramSocket;
  6. import java.net.InetAddress;
  7. public class SendDemo {
  8. public static void main(String[] args) throws IOException {
  9. DatagramSocket ds = new DatagramSocket();
  10. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  11. String line;
  12. while ((line=br.readLine())!=null){
  13. if ("886".equals(line)){
  14. break;
  15. }
  16. byte[] bys = line.getBytes();
  17. DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.115.249"),12345);
  18. ds.send(dp);
  19. }
  20. ds.close();
  21. }
  22. }

接收数据

  1. import java.io.IOException;
  2. import java.net.DatagramPacket;
  3. import java.net.DatagramSocket;
  4. public class ReceiveDemo {
  5. public static void main(String[] args) throws IOException {
  6. DatagramSocket ds = new DatagramSocket(12345);
  7. while (true) {
  8. byte[] bys = new byte[1024];
  9. DatagramPacket dp = new DatagramPacket(bys, bys.length);
  10. ds.receive(dp);
  11. byte[] datas = dp.getData();
  12. int len = dp.getLength();
  13. String dataString = new String(datas, 0, len);
  14. System.out.println("数据为:"+dataString);
  15. }
  16. }
  17. }

TCP协议

先启动服务器端

  1. public class ServerDemo {
  2. public static void main(String[] args) throws IOException {
  3. ServerSocket ss = new ServerSocket(10000);
  4. Socket s = ss.accept();
  5. InputStream is = s.getInputStream();
  6. byte[] bytes = new byte[1024];
  7. int len = is.read(bytes);
  8. String data = new String(bytes,0,len);
  9. System.out.println("接受的数据是:"+data);
  10. ss.close();
  11. }
  12. }

再启动客户端程序

  1. public class ClientDemo {
  2. public static void main(String[] args) throws IOException {
  3. Socket s = new Socket("192.168.217.249", 10000);
  4. OutputStream os = s.getOutputStream();
  5. os.write("hello 你好 java".getBytes());
  6. s.close();
  7. }
  8. }

接受的数据是:hello 你好 java

注意启动顺序,否则将报错

Exception in thread “main” java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.connect0(Native Method) at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:589) at java.net.Socket.connect(Socket.java:538) at java.net.Socket.(Socket.java:434) at java.net.Socket.(Socket.java:211) at icu.itheima_02.ClientDemo.main(ClientDemo.java:9)

增添反馈

  1. public class ServerDemo {
  2. public static void main(String[] args) throws IOException {
  3. ServerSocket ss = new ServerSocket(10000);
  4. Socket s = ss.accept();
  5. InputStream is = s.getInputStream();
  6. byte[] bytes = new byte[1024];
  7. int len = is.read(bytes);
  8. String data = new String(bytes,0,len);
  9. System.out.println("服务器接受的数据是:"+data);
  10. OutputStream os = s.getOutputStream();
  11. os.write("数据已收到".getBytes());
  12. ss.close();
  13. }
  14. }
  1. public class ClientDemo {
  2. public static void main(String[] args) throws IOException {
  3. Socket s = new Socket("192.168.217.249", 10000);
  4. OutputStream os = s.getOutputStream();
  5. os.write("hello 你好 java".getBytes());
  6. InputStream is = s.getInputStream();
  7. byte[] bytes = new byte[1024];
  8. int len = is.read(bytes);
  9. String data = new String(bytes,0,len);
  10. System.out.println("提示:"+data);
  11. s.close();
  12. }
  13. }

键盘录入实现

  1. public class ServerDemo {
  2. public static void main(String[] args) throws IOException {
  3. ServerSocket ss = new ServerSocket(10000);
  4. //监听客户端连接,返回一个Socket对象
  5. Socket s = ss.accept();
  6. BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
  7. String line;
  8. while ((line = br.readLine())!=null) {
  9. System.out.println(line);
  10. }
  11. ss.close();
  12. }
  13. }
  1. public class ClientDemo {
  2. public static void main(String[] args) throws IOException {
  3. Socket s = new Socket("192.168.217.249", 10000);
  4. BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
  5. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
  6. String line;
  7. while ((line = br.readLine())!=null){
  8. if ("886".equals(line)){
  9. break;
  10. }
  11. bw.write(line);
  12. bw.newLine();
  13. bw.flush();
  14. }
  15. s.close();
  16. }
  17. }

写入到文本文件

….

  1. public class ServerDemo {
  2. public static void main(String[] args) throws IOException {
  3. ServerSocket ss = new ServerSocket(10000);
  4. //监听客户端连接,返回一个Socket对象
  5. Socket s = ss.accept();
  6. BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
  7. BufferedWriter bw = new BufferedWriter(new FileWriter("src\\copy.txt"));
  8. String line;
  9. while ((line = br.readLine())!=null) {
  10. System.out.println(line);
  11. bw.write(line);
  12. bw.newLine();
  13. bw.flush();
  14. }
  15. bw.close();
  16. ss.close();
  17. }
  18. }
  1. public class ClientDemo {
  2. public static void main(String[] args) throws IOException {
  3. Socket s = new Socket("192.168.217.249", 10000);
  4. BufferedReader br = new BufferedReader(new FileReader("src\\owx.txt"));
  5. BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
  6. String line;
  7. while ((line = br.readLine())!=null){
  8. if ("886".equals(line)){
  9. break;
  10. }
  11. bw.write(line);
  12. bw.newLine();
  13. bw.flush();
  14. }
  15. br.close();
  16. s.close();
  17. }
  18. }

多线程上传文件

lambda 表达式

image.png

  1. public class MyRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("多线程程序启动了");
  5. }
  6. }
  1. public class Demo {
  2. public static void main(String[] args) {
  3. MyRunnable m = new MyRunnable();
  4. //普通调用
  5. m.run();
  6. //多线程方式调用
  7. Thread thread = new Thread(m);
  8. thread.start();
  9. //匿名内部类方式
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. System.out.println("匿名内部类实现多线程启动了");
  14. }
  15. }).start();
  16. //Lambda表达式的方式
  17. new Thread( () ->{
  18. System.out.println("Lambda表达式调用");
  19. }).start();
  20. }
  21. }

image.png

  1. public interface Eatable {
  2. void eat();
  3. }
  1. public class EatableImpl implements Eatable {
  2. @Override
  3. public void eat() {
  4. System.out.println("一天一苹果,就会没钱钱");
  5. }
  6. }
  1. public class EatableDemo {
  2. public static void main(String[] args) {
  3. Eatable e = new EatableImpl();
  4. useEatable(e);
  5. useEatable(new Eatable() {
  6. @Override
  7. public void eat() {
  8. System.out.println("匿名内部类吃苹果");
  9. }
  10. });
  11. useEatable(()->{
  12. System.out.println("Lambda吃苹果");
  13. });
  14. }
  15. private static void useEatable(Eatable e) {
  16. e.eat();
  17. }
  18. }

练习2 — 带参lambda

  1. public interface Flyable {
  2. void fly(String s);
  3. }
  1. public class FlyableDemo {
  2. public static void main(String[] args) {
  3. useFlyable(new Flyable() {
  4. @Override
  5. public void fly(String s) {
  6. System.out.println("猜猜s是啥?-->"+s);
  7. System.out.println("恭喜你猜对啦!");
  8. }
  9. });
  10. useFlyable((String s)->{
  11. System.out.print("输出s:");
  12. System.out.println(s);
  13. });
  14. }
  15. public static void useFlyable(Flyable f){
  16. f.fly("我想要飞得更高!");
  17. }
  18. }

带参带返回值的Lambda

Variable used in lambda expression should be final or effectively final
在lambda表达式中使用的变量应该是最终的或有效的最终的。

  1. public interface Addable {
  2. int add(int x,int y);
  3. }
  1. public class AddableDemo {
  2. public static void main(String[] args) {
  3. /*
  4. 匿名内部类定义的sum与外部定义的sum互不干扰
  5. */
  6. int aa =1;
  7. int sum = useAddable(new Addable() {
  8. @Override
  9. public int add(int x, int y) {
  10. int aa = 3; //不会显示已定义,不会报错
  11. int sum = x + y;
  12. return sum;
  13. }
  14. });
  15. System.out.println(sum);
  16. /*
  17. 而Lambda中定义的,只能在内部使用
  18. 但是外部定义的,两者内部都可以直接使用
  19. */
  20. int mul1 = useAddable((int x, int y) -> {
  21. int aa = 5; //报错提示:Variable 'aa' is already defined in the scope
  22. int mul = x * y;
  23. return mul;
  24. });
  25. System.out.println(mul1);
  26. }
  27. private static int useAddable(Addable a) {
  28. int sum = a.add(12345, 54321);
  29. return sum;
  30. }
  31. }

Lambda表达式的省略模式

  1. public class AddableDemo {
  2. public static void main(String[] args) {
  3. useAddable(new Addable() {
  4. @Override
  5. public int add(int x, int y) {
  6. return x + y;
  7. }
  8. // @Override
  9. // public void _print(String s) {
  10. // System.out.println(s);
  11. // }
  12. });
  13. //参数类型可省,多个参数不可只省一个,全部省略或全部不
  14. //当执行语句只有一条且带有return,return也可以省略
  15. useAddable((x, y) -> x + y);
  16. //当参数只有一个,可以省略括号
  17. //当执行语句只有一条,可省略大括号{}
  18. useFlyable(s -> System.out.println(s));
  19. }
  20. private static void useAddable(Addable a) {
  21. int sum = a.add(12345, 54321);
  22. System.out.println(sum);
  23. }
  24. public static void useFlyable(Flyable f) {
  25. f.fly("我想要飞得更高!");
  26. }
  27. }

Lambda使用注意事项

  1. public class LambdaDemo {
  2. /*
  3. Lambda使用注意事项
  4. */
  5. public static void main(String[] args) {
  6. useInner(() -> System.out.println("使用Lambda必须要有接口,且接口有且仅有一个方法"));
  7. // 必须有上下文环境,才能推导出Lambda对应的接口
  8. Runnable r = () -> System.out.println("接口1111");
  9. new Thread(r).start();
  10. new Thread(() -> System.out.println("接口22222")).start();
  11. }
  12. private static void useInner(Inner i) {
  13. i.show();
  14. }
  15. }

Lambda表达式与匿名内部类的区别

实现原理不同:
//匿名内部类会产生一个新的字节码 .class文件
//而 Lambda不会产生

  1. public class LambdaDemo {
  2. /*
  3. Lambda与匿名内部类区别
  4. */
  5. public static void main(String[] args) {
  6. //只能实现接口
  7. useInner(() -> System.out.println("使用Lambda必须要有接口,且接口有且仅有一个方法"));
  8. //useAnimal(()-> System.out.println("实现抽象类调用")); //报错
  9. //useStudent(()-> System.out.println("实现具体类调用")); //报错
  10. //匿名内部类会产生一个新的字节码 .class文件
  11. //而 Lambda不会产生
  12. useInner(new Inner() {
  13. @Override
  14. public void show() {
  15. System.out.println("匿名内部类实现接口");
  16. }
  17. });
  18. useAnimal(new Animal() {
  19. @Override
  20. public void method() {
  21. System.out.println("匿名内部类实现抽象类");
  22. }
  23. });
  24. useStudent(new Student() {
  25. @Override
  26. public void study() {
  27. System.out.println("匿名内部类实现具体类");
  28. }
  29. });
  30. }
  31. private static void useInner(Inner i) {
  32. i.show();
  33. }
  34. private static void useAnimal(Animal a) {
  35. a.method();
  36. }
  37. private static void useStudent(Student s) {
  38. s.study();
  39. }
  40. }

接口更新

image.png

  1. public interface MyInterface {
  2. void show1();
  3. void show2();
  4. //默认方法: 使用 default 关键字修饰,可以含有方法体,可以被重写
  5. default void show3(){
  6. System.out.println("俺是默认方法");
  7. }
  8. //静态方法: 也可以拥有方法体
  9. static void show4(){
  10. System.out.println("俺是静态方法");
  11. }
  12. //java 9 新增私有方法
  13. /* 注意:
  14. 默认方法可以调用静态方法和费静态方法
  15. 而静态方法只能调用私有的静态方法
  16. */
  17. private void show5(){
  18. }
  19. }
  1. public class MyInterfaceImplOne implements MyInterface {
  2. @Override
  3. public void show1() {
  4. System.out.println("ImplOne -->show1方法");
  5. }
  6. @Override
  7. public void show2() {
  8. System.out.println("ImplOne -->show2方法");
  9. }
  10. @Override
  11. public void show3() {
  12. System.out.println("默认方法被重写了哎");
  13. }
  14. //静态方法不可被重写
  15. /*@Override
  16. public void show4() {
  17. System.out.println("默认方法被重写了哎");
  18. }*/
  19. }
  1. public class MyInterfaceImplTwo implements MyInterface{
  2. @Override
  3. public void show1() {
  4. System.out.println("ImplTwo -->show1方法");
  5. }
  6. @Override
  7. public void show2() {
  8. System.out.println("ImplTwo -->show2方法");
  9. }
  10. }
  1. public class MyInterfaceDemo {
  2. public static void main(String[] args) {
  3. MyInterface mi1 = new MyInterfaceImplOne();
  4. mi1.show1();
  5. mi1.show2();
  6. MyInterface mi2 = new MyInterfaceImplTwo();
  7. mi2.show1();
  8. mi2.show2();
  9. mi2.show3(); //默认方法
  10. //>>> 默认方法被重写了哎
  11. mi1.show3(); //被重写后的默认方法
  12. //>>> 俺是默认方法
  13. //mi1.show4(); //报错
  14. //>>> 静态方法不可通过接口实现类调用
  15. MyInterface.show4(); //只能通过接口调用
  16. //>>> 俺是静态方法
  17. }
  18. }

方法引用

方法引用符 ::

  1. public interface Printable {
  2. void _print(String s);
  3. }
  1. public class PrintableDemo {
  2. public static void main(String[] args) {
  3. usePrintable(s -> System.out.println("憨憨要"+s));
  4. //>>> 憨憨要开心-的life
  5. //可推导则可省,可根据上下文推导
  6. //方法引用符 ::
  7. System.out.println("开心-的life--区别");
  8. //>>> 开心-的life--区别
  9. usePrintable(System.out::println);
  10. //>>> 开心-的life
  11. }
  12. private static void usePrintable(Printable p) {
  13. p._print("开心-的life");
  14. }
  15. }

Lambda表达式支持的引用方法

引用类方法

类名::静态方法

  1. public interface Converter {
  2. int covert(String s);
  3. }
  1. public class ConverterDemo {
  2. public static void main(String[] args) {
  3. useConverter(s -> Integer.parseInt(s));
  4. //类方法引用
  5. useConverter(Integer::parseInt);
  6. }
  7. private static void useConverter(Converter c) {
  8. int a = c.covert("666");
  9. System.out.println(a);
  10. }
  11. }

引用对象的实例方法

对象::成员方法

  1. public interface Printer {
  2. void printUpperCase(String s);
  3. }
  1. public class PrintString {
  2. public static void static_print(String s){
  3. System.out.println(s.toUpperCase()); //转换为大写
  4. }
  5. public void _print(String s){
  6. System.out.println(s.toUpperCase());
  7. }
  8. }
  1. public class printerDemo {
  2. public static void main(String[] args) {
  3. //Lambda表达式
  4. usePrinter(s -> System.out.println(s.toUpperCase()));
  5. //>>> A
  6. //引用对象的实例方法
  7. usePrinter(PrintString::static_print);
  8. //>>> A
  9. PrintString ps = new PrintString();
  10. usePrinter(ps::_print);
  11. //>>> A
  12. }
  13. private static void usePrinter(Printer p) {
  14. p.printUpperCase("a");
  15. }
  16. }

引用类的实例方法

  1. public interface MyString {
  2. String mySubString(String s,int x,int y);
  3. }
  1. public class MyStringDemo {
  2. public static void main(String[] args) {
  3. //截取输出 "Hello" 的[2,5)之间的字符
  4. useMyString((s, x, y) -> s.substring(x, y));
  5. //>>> llo
  6. useMyString(String::substring);
  7. //>>> llo
  8. }
  9. private static void useMyString(MyString ms) {
  10. String s = ms.mySubString("Hello", 2, 5);
  11. System.out.println(s);
  12. }
  13. }

构造器引用

  1. public interface StudentBuilder {
  2. Student build(String name,int age);
  3. }
  1. import lombok.Data;
  2. @Data
  3. public class Student {
  4. private String name;
  5. private int age;
  6. public Student() {
  7. }
  8. public Student(String name, int age) {
  9. this.name = name;
  10. this.age = age;
  11. }
  12. }
  1. public class StudentDemo {
  2. public static void main(String[] args) {
  3. useStudentBuilder((n,a)-> new Student(n,a));
  4. //>>> Student(name=张飞, age=33)
  5. // Student(name=关羽, age=40)
  6. //构造器引用
  7. useStudentBuilder(Student::new);
  8. //>>> Student(name=张飞, age=33)
  9. // Student(name=关羽, age=40)
  10. }
  11. private static void useStudentBuilder(StudentBuilder sb) {
  12. Student sz = sb.build("张飞",33);
  13. System.out.println(sz);
  14. Student sg = sb.build("关羽",40);
  15. System.out.println(sg);
  16. }
  17. }

函数式接口

image.png

  1. //函数式接口注解标记
  2. @FunctionalInterface
  3. public interface MyInterface {
  4. void show();
  5. //void show1(); 新增方法 注解将提示报错
  6. }
  1. public class MyInterfaceDemo {
  2. public static void main(String[] args) {
  3. MyInterface mi = ()-> System.out.println("函数式接口");
  4. mi.show();
  5. }
  6. }

函数式接口作为方法的参数

  1. public class RunnableDemo {
  2. public static void main(String[] args) {
  3. startThread(new Runnable() {
  4. @Override
  5. public void run() {
  6. System.out.println(Thread.currentThread().getName()+"多线程启动了");
  7. //>>> main多线程启动了
  8. }
  9. });
  10. startThread(()-> System.out.println(Thread.currentThread().getName()+"Lambda多线程启动了"));
  11. //>>> mainLambda多线程启动了
  12. }
  13. private static void startThread(Runnable r) {
  14. r.run();
  15. }
  16. }

函数式接口作为方法的返回值