如何写出优雅、高效、逼格高的Java代码(代码优化、Java新特性、代码规范)

目录

常见代码优化:

if/if-else语句优化

使用提前判断

使用枚举或映射

使用函数式编程

将判断逻辑封装

其他

循环类型代码优化

 Stream API

集合操作

数组操作

异常类型代码优化

tyr-with-resource

使用Java 8的函数式接口简化回调操作

字符串操作代码优化

字符格式化

字符串拼接

 Java 11的字符串方法

Java 14的新特性:多行文本块

多线程代码优化

使用并发集合简化

Java 8的CompletableFuture实现异步编程

其它类别代码优化

延迟计算

对象类型转换

Java 15的新特性:记录(Records)

Java 16的新特性:模式匹配的实例of操作符

Java 9的模块化系统

Java15引入特性:密封类型

Java14:Switch表达式

Java 11:嵌套的Lambda表达式

Java8新特性:自定义注解

Java代码规范


常见代码优化:

if/if-else语句优化

使用提前判断

如果某些条件更常见或更容易满足,将其放在前面判断,以减少不必要的判断。这样可以更快地结束整个条件分支。

eg:

如何写出优雅、高效、逼格高的Java代码(代码优化、Java新特性、代码规范)_第1张图片

    // 修改后:    
    @SneakyThrows
    @PostMapping("/saveFeedBackT")
    @ApiOperation("获用户取评价内容")
    public AjaxResult saveFeedBackT(@ApiParam("教师名称") @RequestParam String teacher,
                                    @ApiParam("评分") @RequestParam Integer rating,
                                    @ApiParam("评价内容") @RequestParam String comment) {
        Preconditions.checkArgument(rating!=null&&teacher!=null,"信息填写不完整");
        //或者  一个参数或者对象可以  Assert.notNull(rating,"信息填写不完整");
        return feedbackTeacherService.saveFeedBackT(teacher,rating,comment);
    }
机制 优点 缺点
Alerrt :断言/警告机制

可读性高,可通过异常处理机制传播栈堆错误,方便找出原因

1)本身会消耗一些性能,开启Assert会产生额外能消耗(idea默认开启)

2)敏感信息被放入栈堆可能会被攻击者利用

3)处理的能力比较弱

PreCondition:前置条件机制 可读性高,内置方法多,处理能力较强

1)本身会消耗一些性能

2)不同方法使用了很多相同的判断,会导致代码冗余(Assert相同,但是Assert一般在生产环境要被禁用或移除)

if语句结合抛出异常 灵活性高,可适应特殊的处理

1)可读性较弱

2)需要手动实现异常处理机制,比较复杂(实现可能出错,如抛出了不相关异常),可维护性较弱

使用枚举或映射

如果有大量的条件和对应的操作,可以使用枚举或映射来简化代码。将条件作为枚举的值或映射的键,将对应的操作封装在枚举常量或映射值中。

       //创建测试数组
       List list = Arrays.asList(1, 2, 3, 4, 5);

        //列表元素中选择出1,2,5并进行打印
       list.forEach(f->{    // 不好的写法
           if (f==1){
               System.out.println("一");
           }
           if (f==2){
               System.out.println("二");
           }
           if (f==5){
               System.out.println("五");
           }
       });


        list.forEach(f->{    // 使用if-else减少判断次数
            if (f==1){
                System.out.println("一");
            }else if(f==2){
                System.out.println("二");
            }else if (f==5){
                System.out.println("五");
            }
        });

        list.forEach(f -> { //使用枚举简化(需要创建枚举类)
            Test t = Test.valueOf(String.valueOf(f));
            System.out.println(t.getI_CN());
        });
        
        list.forEach(f->{   //使用switch表达式 java14引入
            System.out.println(switch (f) {
                case 1 -> "一";
                case 2 -> "二";
                case 5 -> "五";
                default -> "";
            });
        });

使用函数式编程

Java 8 引入的函数式编程可以使代码更简洁和可读。可以使用Lambda表达式、函数接口以及Stream API等功能来处理条件判断。

eg:

        //用于存储大于3的元素
        List A_gt3 = new ArrayList<>(5);   //一般的写法
        for (Integer i : list) {
            if (i>3){
                A_gt3.add(i);
            }
        }

        List B_gt3 = new ArrayList<>(5);   //使用lambda表达式
        list.forEach(i->{
            if (i>3){
                A_gt3.add(i);
            }
        });

        List C_gt3 = list.stream()     //使用stream()流
                .filter(i -> i > 3)
                .toList();
    }

for、foreach、stream效率比较:

    如果数据在1万以内的话,for循环效率高于foreach和stream;如果数据量在10万的时候,stream效率最高,其次是foreach,最后是for。另外需要注意的是如果数据达到100万的话,parallelStream异步并行处理效率最高,高于foreach和for。

将判断逻辑封装

//如果有很多给相同的判断 可以使用Predicate接口将判断逻辑封装成可复用的谓词
// 将一个是否为偶数的判断封装
Predicate isEven = number -> number % 2 == 0;
boolean result = isEven.test(4);

其他

此外,还有的常用做法还有,使用三元表达式,对if判断进行逻辑优化,提出if语句作为公共方法等。

循环类型代码优化

 Stream API

集合操作

        Map map = new HashMap<>();
        map.put("A", 1);
        map.put("B", 2);
        List list = Arrays.asList(1, 2, 3, 4, 5, 5);

        // 相加
        int sum = list.stream().mapToInt(Integer::intValue).sum();
        int sum2 = list.stream().reduce(0, Integer::sum);   //从基础值0的基础上累加
        int sum3 = list.parallelStream().reduce(0, Integer::sum);   //使用并行流相加
        // 获取最大值    //Optional类型可以包装结果为null的值
        Optional max = list.stream().max(Integer::compareTo);
        // 获取最小值
        Optional min = list.stream().min(Integer::compareTo);
        min.ifPresent(System.out::println);

        //直接使用Java 8的Stream API对集合进行统计操作
        IntSummaryStatistics i = list.stream()
                .mapToInt(Integer::intValue)
                .summaryStatistics();
        System.out.println("最大值: " + i.getMax());
        System.out.println("最小值: " + i.getMin());
        System.out.println("总和: " + i.getSum());
        System.out.println("平均值: " + i.getAverage());


        // 去重
        List distinctNumbers = list.stream()
                .distinct()
                .toList();


        //利用lambda表达式 使用方法引用 打印输出
        list.forEach(System.out::println);
        // 遍历所有的键值对 使用Lambda表达式
        map.forEach((key, value) -> System.out.println(key + ": " + value));


        //筛选和映射
        List names = Arrays.asList("aa", "bbb", "ccccc");
        List filteredNames = names.stream()     // 遍历输出的结果为 CCCCC
                .filter(name -> name.length() > 4)
                .map(String::toUpperCase)
                .toList();


        // 分组和聚合
        List people = Arrays.asList(
                new Person("A", 10),
                new Person("B", 15),
                new Person("C", 20)
        );

        Map> personList = people.stream()     //会创建一个新的map
                .collect(Collectors.groupingBy(Person::getAge));

        int totalAge = people.stream()  //累加每个人的年龄
                .mapToInt(Person::getAge)
                .sum();


        // 分组和聚合
        List peoples = Arrays.asList(
                new Person("A", 10),
                new Person("B", 15),
                new Person("C", 20),
                new Person("D", 25)
        );

        // 使用Optional和Stream API链式操作处理嵌套对象
        Optional company = getCompany();
        String companyName = company.flatMap(Company::getDepartment)
                .flatMap(Department::getManager)
                .map(Manager::getName)
                .orElse("Unknown");

数组操作

int[] numbers = {1, 2, 3, 4, 5};
// 数组元素求和
int sum = Arrays.stream(numbers).sum();
// 数组排序
int[] sortedNumbers = Arrays.stream(numbers).sorted().toArray(); 

异常类型代码优化

tyr-with-resource

// 可同时处理多个资源
try (BufferedReader br = new BufferedReader(new FileReader("file1.txt"));
     BufferedWriter bw = new BufferedWriter(new FileWriter("file2.txt"))) {
    // 执行操作
} catch (IOException e) {
    // 处理异常
}

使用Java 8的函数式接口简化回调操作

//不使用lambda表达式
public interface Callback {
    void onSuccess(String result);
    void onFailure(Exception e);
}

public void fetchDataAsync(Callback callback) {
    // 异步获取数据
    try {
        String data = fetchData();
        callback.onSuccess(data);
    } catch (Exception e) {
        callback.onFailure(e);
    }
}

// 使用匿名内部类调用
fetchDataAsync(new Callback() {
    @Override
    public void onSuccess(String result) {
        System.out.println("Success: " + result);
    }

    @Override
    public void onFailure(Exception e) {
        System.err.println("Error: " + e.getMessage());
    }
});


// 使用lambda表达式后
@FunctionalInterface //Java8引入的一个注解,用于标记该接口为函数式接口
public interface Callback {
    void onSuccess(String result);
    void onFailure(Exception e);
}

public void fetchDataAsync(Callback callback) {
    // 异步获取数据
    try {
        String data = fetchData();
        callback.onSuccess(data);
    } catch (Exception e) {
        callback.onFailure(e);
    }
}

// 使用Lambda表达式调用
fetchDataAsync(result -> System.out.println("Success: " + result),
               error -> System.err.println("Error: " + error.getMessage()));

字符串操作代码优化

字符格式化

// 类似于c语言的输出语句 阅读时可以知道传入值的类型(和'+'拼接相比)
String name = "LiMing";
int age = 18;
String message = String.format("My name is %s and I'm %d years old.", name, age);

字符串拼接

使用'+'进行拼接:每执行完一条拼接语句会创建一个新的String对象,在产生对象少时推荐使用

需要多次拼接时:
StringBuilder:线程不安全,效率高,不考虑线程安全时使用(如单线程环境),jdk1.5引入

StringBuffer:方法都是同步,线程安全,效率比StringBuilder低,jdk1.0引入

StringJoiner:适用于两字符串间要拼接相同的字符串,jdk8引入

//demo
StringBuilder s = new StringBuilder();
s.append("A");
s.append(", ");
s.append("B");
s.append(", ");
s.append("C");
String result = s.toString();


StringBuffer s = new StringBuffer();
s.append("A");
s.append(", ");
s.append("B");
s.append(", ");
s.append("C");
String result = s.toString();
                                                                                               

StringJoiner s = new StringJoiner(", ");
s.add("A");
s.add("B");
s.add("C");
String result = s.toString();

 Java 11的字符串方法

// isBlank()和lines()
String text = "Hello\nWorld";
System.out.println(text.isBlank()); // 检查字符串是否为空白
System.out.println(text.lines().count()); // 统计字符串中行的数量

Java 14的新特性:多行文本块

String html = """
              
                  
                      

Hello, World!

"""; System.out.println(html);

多线程代码优化

使用并发集合简化

// 简化前代码 并发时要保证线程安全 所以使用hashtable  
// 这个代码是给一个key,key存在,它的值进行加一操作
 Hashtable hashtable = new Hashtable<>();
        
        synchronized (hashtable) {
            if (!hashtable.containsKey("key")) {
                hashtable.put("key", 0);
            } else {
                hashtable.put("key", hashtable.get("key") + 1);
            }
        }

//简化后
ConcurrentMap concurrentMap = new ConcurrentHashMap<>();
concurrentMap.putIfAbsent("key", 0);
concurrentMap.computeIfPresent("key", (k, v) -> v + 1);

Java 8的CompletableFuture实现异步编程

//直接使用这个类 目的是为了不用手动创建、启动和管理线程
//实现多个任务并行执行
CompletableFuture future1 = CompletableFuture.supplyAsync(() -> task1());
CompletableFuture future2 = CompletableFuture.supplyAsync(() -> task2());
CompletableFuture combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + ", " + result2);
//实现超时处理
CompletableFuture future = CompletableFuture.supplyAsync(() -> task());
try {
    String result = future.get(1, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    // 处理超时情况
}

其它类别代码优化

延迟计算

它能够节省资源,避免重复计算
如在电商网站推迟商品推荐的计算,直到用户进入推荐页面时才进行

Supplier lazyValue = () -> {
    // 执行一些复杂的计算
    return "Hello World!";
};

String value = lazyValue.get(); // 在需要时计算值

对象类型转换

class Student {
    private String name;
    private int age;
    private double score;

    // 省略构造方法和其他方法
    // ...
}
class StudentDTO {
    private String name;
    private int age;

    // 省略构造方法和其他方法
    // ...
}

// 1、可以使用Function类进行类型装换 可适用于复杂场景,比较符合函数式编程代码风格
Function studentToDtoConverter = student -> new StudentDTO(student.getName(), student.getAge());
StudentDTO studentDTO = studentToDtoConverter.apply(student);

// 2、使用BeanUtils.copyProperties(source, target)方法进行类型转换 使用简单明了
StudentDTO studentDTO = new StudentDTO();
BeanUtils.copyProperties(student, studentDTO)

Java 15的新特性:记录(Records)

Records对象:不可变(相当于final修饰),会自动为数据成员生成字段、构造函数、equals()、hashCode() 和 toString() 方法
使用目的:简洁、可减少代码书写  且Records支持模式匹配(instanceof 或 switch检查对象是否与某个类型或模式匹配,并且可以直接获取匹配后的对象属性)
 

//demo
record Person(String name, int age) {}
Person person = new Person("LiMing", 18);
System.out.println(person.name());
System.out.println(person.age());

//模式匹配demo
public void processPerson(Person person) {
    if (person instanceof Person adult && adult.age() >= 18) {
        System.out.println(adult.name() + " 是成人,");
        System.out.println("年龄: " + adult.age());
    }
}

Java 16的新特性:模式匹配的实例of操作符

Object obj = 10;
if (obj instanceof Integer integer) {
    System.out.println("Integer: " + integer);
} else if (obj instanceof String str) {
    System.out.println("String: " + str);
} else {
    System.out.println("Unknown");
}

Java 9的模块化系统

它的目的是提供一种更好的方式来组织和管理 Java 应用程序的代码。通过模块化,可以显式地声明模块之间的依赖关系,增强了代码的可维护性和可扩展性

// module-info.java
//这个文件要放到项目中的模块根目录中
module com.example.myapp {
    requires java.base;
    requires org.apache.commons.lang3;
}

Java15引入特性:密封类型

sealed 关键字:用于修饰类、接口或枚举,将其声明为密封类型。密封类型表示该类型只能被指定的子类继承或实现。使用 sealed 可以限制对密封类型的扩展,从而更好地控制类型的继承结构
permits 关键字:用于在密封类型的声明中列出允许继承或实现的具体子类。只有在 permits 子句中明确列出的类才能继承或实现密封类型。这样,您可以明确指定哪些类允许扩展或实现密封类型,提供更加可控的类型继承关系

//demo
public sealed interface Shape permits Circle, Rectangle {
    double calculateArea();
}

public final class Circle implements Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

public final class Rectangle implements Shape {
    private double width;
    private double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
        return width * height;
    }
}

Java14:Switch表达式

//传统写法
int day = 2;
String dayOfWeek;

switch (day) {
    case 1:
        dayOfWeek = "星期一";
        break;
    case 2:
        dayOfWeek = "星期二";
        break;
    case 3:
        dayOfWeek = "星期三";
        break;
    // 其他...
    default:
        dayOfWeek = "无法识别";
        break;
}
//Switch表达式 switch表达式不需要break关键字
int day = 2;
String dayOfWeek = switch (day) {
    case 1 -> "星期一";
    case 2 -> "星期二";
    case 3 -> "星期三";
    // 其他箭头标签...
    default -> "无法识别";
};

Java 11:嵌套的Lambda表达式

在Java 8中,Lambda表达式不能直接包含嵌套的Lambda表达式。只能通过传递已存在的Lambda表达式作为参数来实现类似的效果。

但是从Java 11开始,嵌套的Lambda表达式被引入,允许在Lambda表达式的主体中包含其他Lambda表达式。这种语法使得编写更复杂的函数式代码变得更加方便。

//demo
Function> add = x -> y -> x + y;

int result = add.apply(1).apply(2);
System.out.println(result); // 输出 3

Java8新特性:自定义注解

//demo
// 自定义的注解 @Color 和 @Colors
@Repeatable(Colors.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Color {
    String value();
}

public @interface Colors {
    Color[] value();
}

//调用
@Color("Red")
@Color("Blue")
public class MyClass {

    public static void main(String[] args) {
        // 获取 MyClass 类上的 @Color 注解
        Color[] colors = MyClass.class.getAnnotationsByType(Color.class);
        for (Color color : colors) {
            System.out.print(color.value());    //输出RedBlue
        }
    }
}

Java代码规范

阿里巴巴java开发手册2020.pdf

链接:

百度网盘 请输入提取码

提取码:8700

最后,

        希望文章对你有所帮助! 

你可能感兴趣的:(java,开发语言)