【最新最热】项目屎山化方案大全(吐血整理!)

你,是否尝尝因为项目代码过于简洁而感到烦躁?

你,是否因为高效美观的代码而常常无法达成公司的代码量考核?

你,是否总是觉得自己的项目打包出来体积太小,无法映衬你长期久坐而日益健硕的大腹?

你,是否常常因为代码中的类型过于明确、函数调用链过短而烦恼无比?

那么来看看这篇文章吧,我将会以我拙劣的代码技术带领你走进一个完美的屎山世界~

想必大部分Java开发人员都会选择SpringBoot作为服务端框架,下述文章中,如果描述web服务项目且没有特殊说明,均视为在SpringBoot项目环境中。

顺带一提,标题没有缺字漏字。

使用拼音!

大家都知道,变量名的命名准则就是要明确它的含义。对于一个母语是中文的人,你理所应当的应该使用拼音作为你的变量名首选,这样才能更快的向其他开发人员传达此变量的作用,同时还能增加你的代码量,让代码整体更加充实紧凑,何乐而不为呢?

👍 Good

String yongHuMing = "张三";
String yongHuChuShengRiQi = "1999/01/02";
YongHu yongHu = new YongHu(yongHuMing, YongHuChuShengRiQi);
@Data
public class YongHu {
  private String yongHuMing;
  private String yongHuChuShengRiQi;
  // ...以下略
}

当然,如果真的过长了,或者你们实际上不通过代码量考核绩效,那么谨慎的使用拼音缩写是个不错的选择。拼音缩写能够完美的同时兼顾拼音带来的母语buff和缩写带来的简洁。

String yhm = "张三";
String yhsr = "1999/01/02";
YongHu yh = new YongHu(yhm, yhsr);
@Data
public class YongHu {
  private String yhm;
  private String yhsr;
  // ...以下略
}

👎 Bad

String username = "张三";
String birthday = "1999/01/02";
User user = new User(username, password);
@Data
public class User {
  private String username;
  private String password;
  // ...以下略
}

冗长且难以理解的英文是国人开发的大敌。

✨ 优质实战案例

image.png

别写逻辑注释!

在互联网开发人员之间流传着这样一句话:「逻辑清晰的优秀代码本身就是注释」。这位开发,你也不希望别人觉得你写的代码逻辑不够清晰吧?

作为公司中不可替代的优质人才之一,你所应当做的或许是时不时的为其他人召开一次培训会,来讲解你的代码逻辑、或者是游走于工位之间,为同事们降下你的恩典。但无论如何,你的选择都不应该是添加注释。

👍 Good

String code = commonQuery.getCityCode();
if (StringUtils.isNotEmpty(commonQuery.getDistrictCode())) {
    code = commonQuery.getDistrictCode();
}
List<Map<String, String>> companyInfo = commonDao.getCompanyInfo(code, type);

for (Map<String, String> map : companyInfo) {
    map.put("name", map.get("name").replace("CompanyName", ""));
    if ("01".equals(type)) {
        map.put("name", map.get("name").substring(0, 2));
    }
}
return companyInfo;

👎 Bad

String type = commonQuery.getType();
// 获取市级编码。如果不存在则尝试使用地区编码
String code = commonQuery.getCityCode();
if (StringUtils.isNotEmpty(commonQuery.getDistrictCode())) {
    code = commonQuery.getDistrictCode();
}
// 根据编码和类型查询companyInfo列表
List<CompanyInfo> companyInfoList = commonDao.getCompanyInfoList(code, type);
for (CompanyInfo companyInfo : companyInfoList) {
    // 移除 companyInfo 名称中的 'CompanyName'(大多数为后缀)
    String name = companyInfo.getName().repleace("CompanyName", "");
    
    // 如果类型是 01,则名称只保留前两个字,因为balabala...
    if ("01".equals(type)) {
       name = name.substring(0, 2));
    } 
    companyInfo.setName(name);
}
return companyInfo;

✨ 优质实战案例

image.png

image.png

别用实体类!

你有没有想过,当你为你的接口参数、接口返回值或者请求第三方接口的返回值指定了一个明确类型的 实体类 ,那么是不是你就是在主动降低你代码的灵活度?实体类的属性和类型是定死的,而如果你使用 Map (或者 List<Map>)类型,那么迎接你的将会是无限的可能性

👍 Good

@PostMapping("/foo")
public Map<String, Object> foo(@RequestBody Map<String, Object> params) {
    Map<String, Object> result = service.foo(params);
    // ❤️ 你可以在这里随便删减你的返回值!
    return result;
}
Map<String, Object> requestParams = createParams(...);
String jsonResponse = HttpClientUtils.doPost("第三方接口url", requestParams);
Map<String, Object> hashMap = JSON.parseObject(resultString, Map.class);
if ("200".equals(hashMap.get("code").toString())) {
   List<Map<String, Object>> liData = (List<Map<String, Object>>) hashMap.get("data");
   // and more ...?
}

👎 Bad

@PostMapping("/foo")
public FooResult foo(@RequestBody FooParams params) {
    FooResult result = service.foo(params);
    // 💔 你不可以在这里随便删减你的返回值。
    return result;
}
FooApiParam param = createParam(...);
FooApiResult result = restTemplate.postForObject("第三方接口url", param, FooApiResult.class);
// and more ...?

✨ 优质实战案例

image.png

image.png

处理你的错误!

错误!哦,天呐!这或许是程序员最不希望看到的东西了,你也是,我也是。那么该怎么办?眼不见为净的道理我相信你我都懂。

👍 Good

List<Foo> resultList = null;
try {
    resultList = fooService.foo();
} catch (Throwable e) {
    e.printStackTrace();             // 将错误扼杀在控制台吧
    resultList = new ArrayList<>();  // 然后恩赐一个默认值
}
return resultList;

这对你或者对前端都是一场充满意义的挑战。当结果为空,到底是谁的问题?这也许会成为你接下来一周的工作量。天呐!想要填满你的工作安排,竟如此轻松。

try {
    fooService.insertInfo(value);
} catch (Exception e) {
    e.printStackTrace(); // 成功了吗?也许只有控制台才知道        
}

插入失败?回滚?异常弹窗?管他呢我的朋友。就像你我的人生,充满了不确定。这次这次执行成功了吗?也许吧,就像一场豪赌。

也许你会觉得将异常信息打印出来还是过于仁慈,那么不妨试着让它们直接销声匿迹

List<Foo> resultList = null;
try {
    resultList = fooService.foo();
} catch (Throwable e) {
    // 错误?不,不需要关心。
    resultList = new ArrayList<>();
}
return resultList;
try {
    fooService.insertInfo(value);
} catch (Exception e) {
    // 成功?失败?又有谁在乎呢。就仿佛发薪日,飘忽不定。
}

👎 Bad

try {
    fooService.insertInfo(value);
} catch (Exception e) {
    // 明确的错误信息只会徒增你的工作量,甚至可能引火烧身。
    logger.error("why?", e);
    throw new FooException("Why?", e);
}

✨ 优质实战案例

image.png

image.png

统一返回值!

统一!规范!标准!这可是大家都喜欢的东西。至少,你的领导和你的同事都很喜欢。当然,也许你并没有真正的思考过这是否是存在必要的。但是,总而言之,先写下一个统一的返回值吧!

👍 Good

@Data
public class MyResult<T> {
    private String msg;
    private Integer code;
    private T data;
} 

wow!多么完美的标准返回值!我真的太爱它了,它看上去是这么的精致、标准…天呐!我现在就已经迫不及待地将它用在我项目的每一个地方了!!

// MyController.java
@RestController
@RequestMapping("/foo")
public class MyController {
    @Autowired
    private MyService service;

    @GetMapping("/api/1")
    public MyResult<?> api1() {
        return service.api1();
    }

    @PostMapping("/api/2")
    public MyResult<?> api2() {
        return service.api2();
    }
}

看呐!多么整齐的接口返回值!

 MyService.java
public interface MyService {
    MyResult<?> api1();
    MyResult<?> api2();
}

 MyServiceImpl.java
@Service
public class MyServiceImpl implements MyService {
    @Override
    public MyResult<?> api1() {
        final MyResult<Data1> result = new MyResult<>();
        try {
            Data1 data = doApi1();
            result.setData(data);
            result.setCode(200);
            result.setMsg("成功");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.setCode(500);
            result.setMsg("错误: " + e.getLocalizedMessage());
        }
        return result;
    }

    @Override
    public MyResult<?> api2() {
        // do something ...
    }

    private Data1 doApi1() {
        // do something ...
    }

    private Data2 doApi2() {
        // do something ...
    }
}

我已经开始为自己这精妙的设计感动到痛哭流涕了。让我来看看,前端是怎么使用我的返回值的呢:

// vue2 + ElementUI
getData(require).then((result) => {
   if (result.code == 200) {
      // 接口成功
      this.data = res.data.list;
   } else {
      // 接口错误
      this.$message.error(res.msg);
      // ...
   }
});

不错!严谨!而且这样的形式,在浏览器f12中也永远不会在看到因接口内部错误而导致的报错了,真的是一举两得!

👎 Bad

再反观下面这些代码:

// MyController.java
@RestController
@RequestMapping("/foo")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class MyController {
    private final MyService service;

    @GetMapping("/api/1")
    public Data1 api1() {
        return service.api1();
    }

    @PostMapping("/api/2")
    public Data2 api2() {
        return service.api2();
    }
}
 MyService.java
public interface MyService {
    Data1 api1();
    Data2 api2();
}

 MyServiceImpl.java
@Service
public class MyServiceImpl implements MyService {
    @Override
    public Data1 api1() {
        return doApi1();
    }

    @Override
    public Data2 api2() {
        Data2 data = doApi2();
        if (...) {
            throw new ApiException(10001, "xxx错误");
        }

        return data;
    }

    private Data1 doApi1() {
        // ...
    }

    private Data2 doApi2() {
        // ...
    }
}
// 仅统一**异常**的返回值
@RestControllerAdvice
public class ApiExceptionHandle {

    @ExceptionHandler(value = ApiException.class)
    public ExceptionResult handlerApiException(ApiException exception){
        return new ExceptionResult(exception.getCode(), exception.getMsg(), exception.getData());
    }

    @ExceptionHandler(value = Exception.class)
    public <E>Message<E> handlerAll(Exception exception){
        return new ExceptionResult(-1, exception.getLocalizedMessage(), exception.toString());
    }
  
}

天呐!这简直…简直是…丑陋!混乱!一个接口、一个Controller中的方法返回值类型都不一样,这又如何能做到标准!我简直不敢想象前端收到这样的响应值会是如何使用的:

// vue2 + ElementUI
getData(require).then((result) => {
    // 接口成功
    this.data = result;
  }).catch(() => {
    // 接口错误
    this.$message.error("服务端异常");
    // ...
  });

哦我的上帝,这实在是太可怕了,居然!居然都不会使用 if(result.code == 200) 判断成功与否就去使用结果,这样不严谨的代码是如何存在于此世的!?

✨ 优质实战案例

image.png

image.png

image.png

image.png

image.png

增加依赖!

依赖当然是越多越好的啦,难道你希望别人问你“你们项目都用了什么技术”的时候,你却说不上来几个东西吗?

👍 Good

<!-- 省略其余基本的spring boot相关依赖... -->


<!-- long! common! util! -->

<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>...</version>
</dependency>

<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>...</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>...</version>
</dependency>


<!-- JSON! -->

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
</dependency>


<!-- 分页!分页!数据库! -->

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>...</version>
</dependency>

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>...</version>
</dependency>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>...</version>
</dependency>


<!-- http! -->

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>...</version>
</dependency>

👎 Bad

<!-- 其余spring boot依赖省略... -->
<!-- 需要? 那就加。官方有? 那最好。 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 也许你应该尝试一下spring-data -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>...</version>
</dependency>

更多的工具类!

工具类即生产力。你难道不会觉得一个全局的 static 工具类,无论何种形式他都是最帅的吗?你完全可以无视上下文环境,或者任何的缓存、线程安全亦或是动态属性。全局是一个具有魅力的词,而工具类则是它最好的表现形式。

👍 Good

public class HttpClientUtils {
   private static final String DEFAULT_CHARSET = "UTF-8";
   
   public static String doGet(String url, Map<String, String> param) { 
      // ...
   }
   
   public static String doGet(String url) {
        // ...
   }
   
   public static String doPost(String url, Map<String, String> param) {
      // ...
   }
   
   public static String doPost(String url, Map<String, String> headMap, Map<String, String> param) {
      // ...
   }
}
public class JsonUtils {
   
	/**
	 * ...
         *
	 * @throws JsonProcessingException
	 */
	public static String mapToString(Map<String, ?> map){
            return objectToString(map);
	}
	
	/**
	 * ...
         *
	 * @throws JsonProcessingException
	 */
	public static String objectToString(Object obj) {
            ObjectMapper mapper = new ObjectMapper();
            try {
                return mapper.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return null;
            }
	}
}

👎 Bad

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class DemoServiceImpl {
    private final RestTemplate restTemplate;

    public Data getData() {
        return restTemplate.getForObject("http://api.example.com/api2", Data.class);
    }

    public Data2 getData2() {
        Param param = new Param();
        // ...
        return restTemplate.postForObject("http://api.example.com/api2", param, Data2.class);
    }
}

失去了工具类,就仿佛失去耶路撒冷。 ———————— 《说过》没有人 著

但是人生的旅途并非总是一帆风顺,写工具类的旅途也是。也许你会发现,并不是所有东西都会一开始就存在于全局中,它仿佛失去了被 static 宠幸的权利,卑微的存在于名为 「生命周期」「上下文」 的深渊中,任由宿命摆弄… 但是没关系!我们可以等,等到时机成熟、等到春暖花开、等到天荒地老、等到…它来到你的身边。

👍 Good

@Component
public class SpringContextUtil implements ApplicationContextAware{
    private static ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringContextUtil.applicationContext == null) {
        	SpringContextUtil.applicationContext = applicationContext;
        }
    }
 
    /**
     * 获取applicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    /**
     *通过name获取 Bean.
     */
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }
 
    /**
     * 通过class获取Bean.
     */
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }
 
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }  
}

👎 Bad

@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class Fooervice {
   private final TheTypeYouNeed1 type1;
   private final TheTypeYouNeed2 type2;
   private final TheTypeYouNeed3 type3;
   private final TheTypeYouNeed4 type4;
   private final TheTypeYouNeed5 type5;
   // ...
   
}

image.png

✨ 优质实战案例

image.png

image.png

Stream!Stream!Stream!

你听说过Java8和Lambda吗?什么?你居然不知道?拜托,这超帅的好嘛!我的梦想就是有朝一日,我的项目里充满了 Stream,而不是那些low爆的 List。难道你不觉得一行写完所有逻辑很cool嘛?

👍 Good

List<Map<String, Object>> liData = hashMap.get("data");
liData = liData.stream().sorted(Comparator.comparing(e -> Integer.valueOf(e.get("sort").toString()))).collect(Collectors.toList());
Map<Object, List<Map<String, Object>>> ssqxMap = dataList.stream().collect(Collectors.groupingBy(x -> x.get("ssqx")));
                    
Set<Object> keySet = ssqxMap.keySet();
if (keySet.contains(commonQuery.getDistrictCode())) {
   dataList = ssqxMap.get(commonQuery.getDistrictCode());
} else {
   dataList = new ArrayList<>();
}

👎 Bad

liData.sort(Comparator.comparing(Data::getSortValue));
final Set<String> set = new HashSet<>();
final ArrayList<Data> values = getDataList();
for (Data data : values) {
    set.add(data.getFoo());
}

 or by stream
Set<String> setByStream = values.stream()
        .map(Data::getFoo)
        .collect(Collectors.toSet());

✨ 优质实战案例

image.png

image.png

image.png

警告!警告!警告!

IDE中的警告越多,这越能体现你独特的思维方式。怎么?你难道不知道吗?无视它!区区IDE怎么可能理解你精妙的高效代码。

👍 Good

image.png

image.png

👎 Bad

image.png

尾声

感谢您能够看完这篇充满了阴阳怪气的水文。

本文仅供娱乐,如果能博君一笑,便是我最大的荣幸。

为了表示感谢,我在这里祝愿看到这里的诸位也能寻得属于自己的代码美学、拥有一份令自己满意的工作、感受到社会带给你的温暖真情。

特别鸣谢

感谢 state-of-the-art-shitcode 为文本提供部分灵感。

感谢某不知名外包公司的项目为本文提供编撰动机和大量优秀案例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值