0
点赞
收藏
分享

微信扫一扫

Java 编程知识博客:高级特性与实战技巧(第二篇)

在上一期中,我们探讨了 Java 的基础语法、面向对象核心特性、集合框架及异常处理。本期将深入 Java 高级特性,这些内容是从初级开发者迈向中高级的关键,也是企业级开发中的高频应用点。


一、泛型:类型安全的 "保护伞"

泛型(Generic)是 JDK 5 引入的特性,核心作用是在编译期检查类型安全性,避免运行时出现ClassCastException,同时消除繁琐的强制类型转换。

1. 泛型的基本使用

泛型可用于类、接口和方法,语法为<类型参数>,通常用单个大写字母表示(如T表示 Type,E表示 Element)。

(1)泛型类

// 定义泛型类:存储任意类型的对象
public class Box<T> {
    private T content;
    
    public void setContent(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
    
    public static void main(String[] args) {
        // 使用时指定类型(String)
        Box<String> stringBox = new Box<>();
        stringBox.setContent("Hello Generics");
        String str = stringBox.getContent(); // 无需强制转换
        
        // 编译期检查:不能放入其他类型
        // stringBox.setContent(123); // 编译报错
    }
}


(2)泛型方法

public class GenericMethodDemo {
    // 泛型方法:交换数组中两个元素的位置
    public static <T> void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    
    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3, 4};
        swap(intArray, 0, 3); // 交换整数数组
        
        String[] strArray = {"A", "B", "C"};
        swap(strArray, 1, 2); // 交换字符串数组
    }
}


2. 泛型通配符:灵活的类型限制

当需要接收 "任意泛型类型" 时,需使用通配符?,配合extendssuper实现灵活的类型限制:

  • <? extends T>:上限通配符,只能接收T及其子类(只读,不能添加元素,因不确定具体类型);
  • <? super T>:下限通配符,只能接收T及其父类(可写,能添加T及其子类元素)。

示例

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

public class WildcardDemo {
    // 打印所有Number及其子类(如Integer、Double)的集合
    public static void printNumberList(List<? extends Number> list) {
        for (Number num : list) {
            System.out.println(num);
        }
        // list.add(100); // 编译报错:不能添加元素(不确定具体类型)
    }
    
    // 向集合中添加Integer及其子类(实际只有Integer,因Integer是final类)
    public static void addIntegers(List<? super Integer> list) {
        list.add(100); // 合法
        list.add(200); // 合法
    }
    
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        intList.add(1);
        intList.add(2);
        printNumberList(intList); // 合法:Integer是Number的子类
        
        List<Object> objList = new ArrayList<>();
        addIntegers(objList); // 合法:Object是Integer的父类
    }
}


二、Lambda 表达式与函数式编程

JDK 8 引入的 Lambda 表达式,彻底改变了 Java 的编程风格,让代码更简洁,同时支持函数式编程(将函数作为参数传递)。

1. Lambda 表达式:简化匿名内部类

对于只包含一个抽象方法的接口(称为函数式接口),Lambda 表达式可替代冗长的匿名内部类。

语法(参数列表) -> { 方法体 }(参数类型可省略,单参数可省括号,单语句可省大括号和 return)

示例

import java.util.Arrays;
import java.util.List;

public class LambdaDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        
        // 传统匿名内部类:遍历集合
        names.forEach(new java.util.function.Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println(name);
            }
        });
        
        // Lambda表达式简化:效果同上
        names.forEach(name -> System.out.println(name));
        
        // 更简洁的方法引用(::):当参数直接传递给方法时
        names.forEach(System.out::println);
    }
}


2. Stream API:集合操作的 "瑞士军刀"

Stream API 配合 Lambda,能以声明式方式处理集合(类似 SQL 查询),支持过滤、映射、排序、聚合等操作,代码更简洁易读。

Stream 操作流程

  1. 创建流:从集合、数组等获取流(list.stream());
  2. 中间操作:过滤(filter)、映射(map)、排序(sorted)等(返回新流,可链式调用);
  3. 终端操作:收集(collect)、计数(count)、遍历(forEach)等(触发实际计算)。

示例

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

public class StreamDemo {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
            new Student("Alice", 90, "Math"),
            new Student("Bob", 85, "English"),
            new Student("Charlie", 95, "Math"),
            new Student("David", 75, "Math")
        );
        
        // 需求:找出数学(Math)成绩>=90分的学生姓名,按成绩降序排列
        List<String> result = students.stream()
            // 过滤:只保留Math学科且成绩>=90
            .filter(s -> "Math".equals(s.getSubject()) && s.getScore() >= 90)
            // 排序:按成绩降序
            .sorted((s1, s2) -> Integer.compare(s2.getScore(), s1.getScore()))
            // 映射:提取姓名
            .map(Student::getName)
            // 收集结果到List
            .collect(Collectors.toList());
        
        System.out.println(result); // 输出:[Charlie, Alice]
    }
    
    static class Student {
        private String name;
        private int score;
        private String subject;
        
        // 构造器、getter省略
        public Student(String name, int score, String subject) {
            this.name = name;
            this.score = score;
            this.subject = subject;
        }
        
        public String getName() { return name; }
        public int getScore() { return score; }
        public String getSubject() { return subject; }
    }
}


三、并发编程:应对多线程场景

在现代应用中,并发编程是处理高并发请求的核心,Java 提供了完善的多线程支持。

1. 线程的创建方式

Java 中创建线程有 3 种核心方式:

(1)继承 Thread 类

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Thread: " + i);
            try {
                Thread.sleep(100); // 休眠100ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程(调用run())
    }
}


(2)实现 Runnable 接口(推荐,避免单继承限制)

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行逻辑
    }
    
    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}


(3)使用 Callable 和 Future(可获取返回值)

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum; // 返回计算结果
    }
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(new MyCallable());
        new Thread(task).start();
        
        // 获取线程返回值(会阻塞直到计算完成)
        System.out.println("1-100的和:" + task.get());
    }
}


2. 线程池:高效管理线程资源

频繁创建 / 销毁线程会消耗大量资源,线程池可复用线程,控制并发数,是企业开发的首选。

Java 通过ExecutorService框架提供线程池实现,常用的有:

  • FixedThreadPool:固定大小的线程池;
  • CachedThreadPool:可缓存的线程池(线程数随需求变化);
  • ScheduledThreadPool:支持定时任务的线程池。

示例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建固定大小为5的线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);
        
        // 提交10个任务
        for (int i = 0; i < 10; i++) {
            final int taskNum = i;
            executor.submit(() -> {
                System.out.println("执行任务 " + taskNum + ",线程:" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        
        executor.shutdown(); // 关闭线程池
    }
}


3. 线程安全:避免并发问题

多线程共享资源时可能出现线程安全问题(如数据不一致),常用解决方案:

  • synchronized:关键字,修饰方法或代码块,保证同一时间只有一个线程执行;
  • Lock:接口(如ReentrantLock),更灵活的锁机制(可中断、超时获取锁);
  • 原子类java.util.concurrent.atomic包下的类(如AtomicInteger),通过 CAS 机制实现无锁线程安全。

示例:synchronized 的使用

public class SynchronizedDemo {
    private int count = 0;
    
    // 同步方法:锁住当前对象
    public synchronized void increment() {
        count++;
    }
    
    public static void main(String[] args) throws InterruptedException {
        SynchronizedDemo demo = new SynchronizedDemo();
        
        // 1000个线程,每个线程执行1000次自增
        for (int i = 0; i < 1000; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    demo.increment();
                }
            }).start();
        }
        
        Thread.sleep(2000); // 等待所有线程执行完毕
        System.out.println("count = " + demo.count); // 输出1000000(线程安全)
    }
}


四、实战案例:简易 REST 接口开发

结合上述知识点,我们用 Spring Boot 开发一个简易的用户管理接口,包含 CRUD 操作。

1. 项目结构

src/main/java/com/example/demo/
├── DemoApplication.java       // 启动类
├── controller/UserController.java  // 接口层
├── service/UserService.java        // 业务层
├── repository/UserRepository.java  // 数据访问层
└── model/User.java                 // 实体类


2. 核心代码

(1)实体类User.java

package com.example.demo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private int age;
    
    // 构造器、getter、setter省略
}


(2)数据访问层UserRepository.java

package com.example.demo.repository;

import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;

// 继承JpaRepository,自动获得CRUD方法
public interface UserRepository extends JpaRepository<User, Long> {
    // 自定义查询:根据年龄查询用户
    List<User> findByAgeGreaterThan(int age);
}


(3)业务层UserService.java

package com.example.demo.service;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    
    // 获取所有用户
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    // 根据ID获取用户
    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }
    
    // 创建用户
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    // 更新用户
    public User updateUser(Long id, User userDetails) {
        return userRepository.findById(id)
            .map(user -> {
                user.setName(userDetails.getName());
                user.setAge(userDetails.getAge());
                return userRepository.save(user);
            })
            .orElseThrow(() -> new RuntimeException("User not found"));
    }
    
    // 删除用户
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}


(4)接口层UserController.java

package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    // GET /api/users:获取所有用户
    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }
    
    // GET /api/users/{id}:获取单个用户
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        return userService.getUserById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    
    // POST /api/users:创建用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    
    // PUT /api/users/{id}:更新用户
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
        try {
            return ResponseEntity.ok(userService.updateUser(id, user));
        } catch (RuntimeException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    // DELETE /api/users/{id}:删除用户
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}


五、下期预告:性能优化与架构设计

本期我们讲解了泛型、Lambda、并发编程及实战案例,下期将聚焦:

  1. JVM 核心机制:内存模型、垃圾回收、类加载;
  2. 性能优化技巧:代码层面、JVM 参数、数据库优化;
  3. 设计模式:常用模式(单例、工厂、代理等)在 Java 中的实现;
  4. 分布式基础:RPC、分布式锁、服务注册与发现。

关注本博客,持续获取 Java 进阶干货!如有疑问或想深入的主题,欢迎留言讨论。

举报

相关推荐

0 条评论