关于java:奇淫技巧如何写最少的代码

51次阅读

共计 5257 个字符,预计需要花费 14 分钟才能阅读完成。

前言

因为性情起因,笔者很难沉下心来进行庄重的零碎学习,总是喜爱折腾一些奇淫技巧,十分喜爱代码设计,扣代码的细节,所以本次分享一下我所晓得的 如何写起码的代码 的小技巧,如果你有更好的计划,欢送在评论区留言,计划很棒的话,加我微信,为你送上冬天的一杯奶茶~

Java:我想返回多个返回值

秀一下 Go 的多返回值:

package main
import "fmt"

// 返回 X + Y 和 X * Y
func Computer(X, Y int) (int, int) {return X + Y, X * Y}

家喻户晓,Java 仅反对繁多返回值,个别状况下如果须要返回多个对象,咱们会依据代码语义抉择容器或者新建一个新的类,把咱们须要的数据包起来。

这样做有没有问题?当然没有问题,然而瑕疵就在于:可能会产生没啥语义但又不得不存在的 两头类,我集体十分探讨该类代码,那么该如何解决这种问题呢?

首先须要意识到,解决方案必须满足几个要求:

  • 代码可复用
  • 语义要清晰
  • 平安

既然如此,咱们能够采纳 泛型 来满足复用、语义清晰的要求,用 两头类 来满足代码安全性的要求,代码如下:

public class MultipleTwoReturn<A, B> {
    /** 第一个返回值 **/
    private final A first;

    /** 第二个返回值 **/
    private final B second;

    public MultipleTwoReturn(A first, B second) {
        this.first = first;
        this.second = second;
    }

    // 省略 Get 办法
}

同时,咱们能够依赖于 继承,让该工具类拓展更多的参数:

public class MultipleThreeReturn<A, B, C> extends MultipleTwoReturn<A, B> {

    /** 第三个返回值 **/
    private final C third;

    public MultipleThreeReturn(A first, B second, C third) {super(first, second);
        this.third = third;
    }
}

测试类:

public class MultipleApp {public static void main(String[] args) {MultipleTwoReturn<Integer, String> returnTest = MultipleApp.getReturnTest();
        System.out.println(returnTest.getFirst());
        System.out.println(returnTest.getSecond());
    }

    private static MultipleTwoReturn<Integer, String> getReturnTest() {MultipleTwoReturn<Integer, String> demo = new MultipleTwoReturn<>(0, "Kerwin Demo.");
        return demo;
    }
}

实质还是 一般对象 ,然而加上 泛型 后威力剧增!因为在办法定义时就强制了 泛型束缚,语义十分清晰,同时能够齐全杜绝上述的无语义两头类,当然一些必要的,有业务含意的组装类,不倡议应用这种形式。

泛型:我想 new 一个对象

大家在学 Java 泛型之初有没有这种想法?我想利用 <T> 作为泛型束缚,却须要 new 一个 T,然而 Java 它new 不进去啊 ????

很久之前我在写一个通用的 Java 爬虫接口,外面有一个性能就是 传入指标网页的即可获取到针对不同网页设计的 Bean,大略如下所示:

public interface SpiderBeansHandle<T> {
    /** 获取 Url **/
    String getUrl();

    /** 获取 Cookie **/
    String getCookie();

    /** 获取 CSS selector **/
    String getSelector();
    
    // ....
 }

两头要害的一点即如何获取到这个 Bean,那个时候我只有一个想法:new 一个 T

事实证明,我过于天真了 ????

然而换种思路,既然 new 不进去,那我就返回一下吧,于是代码出炉了~

public interface SpiderBeansHandle<T> {

    /**
     * 获取 Url
     */
    String getUrl();

    /**
     * 获取 Cookie
     */
    String getCookie();

    /***
     * 获取 CSS selector
     */
    String getSelector();

    /***
     * 解析 Element
     * @param element  element
     */
    T parseElement(Element element);

    /***
     * Get Beans
     * @param handle  Bean 对象 | handle 对象
     * @param <T>     Bean 类型
     * @return        List<Beans>
     */
    static <T> List<T> getBeans(SpiderBeansHandle<T> handle) {List<T> list = new ArrayList<>();
        List<Element> elements = SpiderUtils.getElementWithCookie(handle.getUrl(), handle.getSelector(), handle.getCookie());
        for (Element element : elements) {T bean = handle.parseElement(element);
            if (bean != null) {list.add(bean);
            }
        }
        return list;
    }
}

要害一步就在于:

/***
 * 解析 Element
 * @param element  element
 */
T parseElement(Element element);

那么这个小技巧有什么用呢?认真看会不会感觉它像一种设计模式的变形体?没错!假相只有一个:模板办法模式

我刚提到了我须要一个 解决爬虫的通用接口,因为简略爬虫无非就是拿到 url 而后申请,解析细节封装到本身的 Bean 里,而后获取一个列表,那么在开发业务代码的时候相似,必定有某些场景和需要具备高度的一致性,那么应用这种设计方案即可大大的缩小反复代码~

办法:你到底想干嘛?

咱们在写代码的时候有没有遇到过这种问题?写了一个工具类办法,然而性能又过于繁多,虽说繁多准则好吧,然而一个小逻辑写一堆办法,总感觉不得劲,如何解决咧?

Java8 提供的函数式编程即可帮咱们肯定水平上解决这种问题,如:

// 写一个获取文件列表,且判断是否为 txt 结尾的工具类办法,老手会这么写
public static File getFileWithTxt(String path) throws IOException {File file = new File(path);
    if (!file.exists()) {throw new IOException("File is not exist.");
    }

    if (file.getName().endsWith(".txt")) {return file;}

    return null;
}

新手个别会把 .txt 作为参数传入,然而某一天我须要判断文件大小,文件长度,甚至是文件内容的时候,我该咋办?再写 N 个?

最好的计划即传入 Predicate 谓词,让调用者 自定义解决逻辑,而后再把最罕用的逻辑基于该办法复写一下,拓展性 Max!代码如下:

/***
 * 文件夹谓词匹配
 * @param file          文件
 * @param predicate     谓词匹配
 * @return              List<File>
 * @throws IOException  IOException
 */
public static List<File> listFilesInDirWithFilter(File file, Predicate<String> predicate) throws IOException {if (!file.exists()) {throw new IOException("File is not exist.");
     }

    List<File> fileList = new ArrayList<>();
    if (file.isDirectory()) {File[] files = file.listFiles();
        for (File f : Objects.requireNonNull(files)) {fileList.addAll(listFilesInDirWithFilter(f, predicate));
         }
    } else {if (predicate.test(file.getName())) {fileList.add(file);
        }
    }
    return fileList;
}

相似的还比如说解决 IO,间接上代码:

public static void readLine(BufferedReader br, Consumer<String> handle, boolean close) {
    String s;
    try {while (((s = br.readLine()) != null)) {handle.accept(s);
        }
    } catch (IOException e) {e.printStackTrace();
    } finally {if (close && br != null) {
            try {br.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }
}

办法 说你到底想干嘛?!算了,你想干嘛就干嘛吧,请随便????~

重载:写的更多也是为了写的更少

写的更多也是为了写的更少 ,这句话乍一听感觉十分矛盾,然而编程教训比拟丰盛的小伙伴应该能领会到 办法重载 的威力,尤其是在写工具类或者底层接口的时候,倡议大家先写一个大而全的 外部办法,而后一点点去依据须要重载它,会有意想不到的益处。

最简略的例子,如下:

// Root 办法
private static void readLine(BufferedReader br, Consumer<String> handle, boolean close) {
    String s;
    try {while (((s = br.readLine()) != null)) {handle.accept(s);
        }
    } catch (IOException e) {e.printStackTrace();
    } finally {if (close && br != null) {
            try {br.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }
}

// 重载办法一
public static void readLine(String path, Consumer<String> handle, boolean close) {
    try {BufferedReader br = new BufferedReader(new FileReader(path));
        readLine(br, handle, close);
    } catch (FileNotFoundException e) {e.printStackTrace();
    }
}

// 重载办法二
public static void readLine(String path, Consumer<String> handle) {readLine(path, handle, true);
}

重载 能够让咱们的办法调用形式变得丰富多彩,在语义明确的状况下,写代码有如神助,配合函数式编程,能够让工具类或者底层接口的能力大大加强。

同时,当咱们须要调整某一个办法逻辑时,也能够应用 持续重载 的形式,将影响面降到最小,尽量不动其余模块的代码。

终极:从设计模式到形象

与其说是 如何写起码的代码 ,不如说是: 如何只写真正有价值的代码

面对这种问题的时候,咱们第一反馈必定就是设计模式了,例如上文的泛型章节提到的 模板办法模式,小小的举荐一下我之前的文章:

  • 【一起学系列】之模板办法:写 SSO 我只有 5 分钟
  • 设计模式总篇:从为什么须要准则到理论落地

通过良好的设计模式或者其变形体,咱们能够失去高内聚低耦合的代码,这是一个十分好的思路。

另一个思路,所有人都认同一点:程序 = 算法 + 数据结构 ,抉择好正确的数据结构能够事倍功半,比如说咱们做 相似文件夹需要 的时候,会想到应用 链表 或者 构造,在做如:如何高效的给用户发送生日短信 时会想到用 构造(用以后工夫比照堆中的最大值,满足则持续迭代,缩小遍历)等等。

这其实都是形象,或深或浅而已,我最开始学习 Java 的时候,老师会说一句话:万物皆为对象,咱们来看看下面的技巧各自对应着什么?

  • 多返回值:封装对象 + 泛型束缚
  • 泛型:封装对象的公共接口,高度形象
  • 函数式办法:把办法当作一个对象
  • 重载:对象办法(行为)的一直演变

所以如何只写真正有价值的代码?官网一点的话就是:把变动的形象进去,那么到底该怎么抽?

这就须要咱们一点点的去摸索了,毕竟 奇淫技巧 只是小道尔,不过我会始终摸索上来。

最初

如果你感觉这篇内容对你有帮忙的话:

  1. 当然要点赞反对一下啦~
  2. 另外,搜寻并关注公众号「是 Kerwin 啊」,一起在技术的路上走上来吧~ ????

正文完
 0