国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁(yè) Java Java基礎(chǔ) 你必須了解的java中的異常

你必須了解的java中的異常

Nov 29, 2019 pm 05:21 PM
java

你必須了解的java中的異常

一.?異常的定義(推薦:java視頻教程

在《java編程思想》中這樣定義?異常:阻止當(dāng)前方法或作用域繼續(xù)執(zhí)行的問(wèn)題。雖然java中有異常處理機(jī)制,但是要明確一點(diǎn),決不應(yīng)該用"正常"的態(tài)度來(lái)看待異常。絕對(duì)一點(diǎn)說(shuō)異常就是某種意義上的錯(cuò)誤,就是問(wèn)題,它可能會(huì)導(dǎo)致程序失敗。之所以java要提出異常處理機(jī)制,就是要告訴開(kāi)發(fā)人員,你的程序出現(xiàn)了不正常的情況,請(qǐng)注意。

記得當(dāng)初學(xué)習(xí)java的時(shí)候,異??偸歉悴惶宄?,不知道這個(gè)異常是什么意思,為什么會(huì)有這個(gè)機(jī)制?但是隨著知識(shí)的積累逐漸也對(duì)異常有一點(diǎn)感覺(jué)了。舉一個(gè)例子來(lái)說(shuō)明一下異常的用途。

public class Calculator {
    public int devide(int num1, int num2) {
        //判斷除數(shù)是否為0
        if(num2 == 0) {
            throw new IllegalArgumentException("除數(shù)不能為零");
        }
         
        return num1/num2;
    }
}

看一下這個(gè)類中關(guān)于除運(yùn)算的方法,如果你是新手你可能會(huì)直接返回計(jì)算結(jié)果,根本不去考慮什么參數(shù)是否正確,是否合法(當(dāng)然可以原諒,誰(shuí)都是這樣過(guò)來(lái)的)。但是我們應(yīng)盡可能的考慮周全,把可能導(dǎo)致程序失敗的"苗頭"扼殺在搖籃中,所以進(jìn)行參數(shù)的合法性檢查就很有必要了。

其中執(zhí)行參數(shù)檢查拋出來(lái)的那個(gè)參數(shù)非法異常,這就屬于這個(gè)方法的不正常情況。正常情況下我們會(huì)正確的使用計(jì)算器,但是不排除粗心大意把除數(shù)賦值為0。如果你之前沒(méi)有考慮到這種情況,并且恰巧用戶數(shù)學(xué)基礎(chǔ)不好,那么你完了。但是如果你之前考慮到了這種情況,那么很顯然錯(cuò)誤已在你的掌控之中。

二. 異常掃盲行動(dòng)

今天和別人聊天時(shí)看到一個(gè)笑話:世界上最真情的相依,是你在try我在catch。無(wú)論你發(fā)神馬脾氣,我都默默承受,靜靜處理。 大多數(shù)新手對(duì)java異常的感覺(jué)就是:try...catch...。沒(méi)錯(cuò),這是用的最多的,也是最實(shí)用的。我的感覺(jué)就是:java異常是從"try...catch..."走來(lái)。

首先來(lái)熟悉一下java的異常體系:

Throwable 類是 Java 語(yǔ)言中所有錯(cuò)誤或異常的超類(這就是一切皆可拋的東西)。它有兩個(gè)子類:Error和Exception。

Error:用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問(wèn)題。這種情況是很大的問(wèn)題,大到你不能處理了,所以聽(tīng)之任之就行了,你不用管它。比如說(shuō)VirtualMachineError:當(dāng) Java 虛擬機(jī)崩潰或用盡了它繼續(xù)操作所需的資源時(shí),拋出該錯(cuò)誤。好吧,就算這個(gè)異常的存在了,那么應(yīng)該何時(shí),如何處理它呢??交給JVM吧,沒(méi)有比它更專業(yè)的了。

Exception:它指出了合理的應(yīng)用程序想要捕獲的條件。Exception又分為兩類:一種是CheckedException,一種是UncheckedException。

這兩種Exception的區(qū)別主要是CheckedException需要用try...catch...顯示的捕獲,而UncheckedException不需要捕獲。通常UncheckedException又叫做RuntimeException。

我們常見(jiàn)的RuntimeExcepiton有IllegalArgumentException、IllegalStateException、NullPointerException、IndexOutOfBoundsException等等。對(duì)于那些CheckedException就不勝枚舉了,我們?cè)诰帉?xiě)程序過(guò)程中try...catch...捕捉的異常都是CheckedException。io包中的IOException及其子類,這些都是CheckedException。

三. 異常的使用

在異常的使用這一部分主要是演示代碼,都是我們平常寫(xiě)代碼的過(guò)程中會(huì)遇到的(當(dāng)然只是一小部分),拋磚引玉嗎!

例1. 這個(gè)例子主要通過(guò)兩個(gè)方法對(duì)比來(lái)演示一下有了異常以后代碼的執(zhí)行流程。

public static void testException1() {
        int[] ints = new int[] { 1, 2, 3, 4 };
        System.out.println("異常出現(xiàn)前");
        try {
            System.out.println(ints[4]);
            System.out.println("我還有幸執(zhí)行到嗎");// 發(fā)生異常以后,后面的代碼不能被執(zhí)行
        } catch (IndexOutOfBoundsException e) {
            System.out.println("數(shù)組越界錯(cuò)誤");
        }
        System.out.println("異常出現(xiàn)后");
    }
    /*output:
    異常出現(xiàn)前
    數(shù)組越界錯(cuò)誤
    4
    異常出現(xiàn)后
    */
public static void testException2() {
        int[] ints = new int[] { 1, 2, 3, 4 };
        System.out.println("異常出現(xiàn)前");
        System.out.println(ints[4]);
        System.out.println("我還有幸執(zhí)行到嗎");// 發(fā)生異常以后,他后面的代碼不能被執(zhí)行
    }

首先指出例子中的不足之處,IndexOutofBoundsException是一個(gè)非受檢異常,所以不用try...catch...顯示捕捉,但是我的目的是對(duì)同一個(gè)異常用不同的處理方式,看它會(huì)有什么不同的而結(jié)果(這里也就只能用它將就一下了)。異常出現(xiàn)時(shí)第一個(gè)方法只是跳出了try塊,但是它后面的代碼會(huì)照樣執(zhí)行的。

但是第二種就不一樣了直接跳出了方法,比較強(qiáng)硬。從第一個(gè)方法中我們看到,try...catch...是一種"事務(wù)性"的保障,它的目的是保證程序在異常的情況下運(yùn)行完畢,同時(shí)它還會(huì)告知程序員程序中出錯(cuò)的詳細(xì)信息(這種詳細(xì)信息有時(shí)要依賴于程序員設(shè)計(jì))。

例2. 重新拋出異常

public class Rethrow {
    public static void readFile(String file) throws FileNotFoundException {
        try {
            BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.err.println("不知道如何處理該異常或者根本不想處理它,但是不做處理又不合適,這是重新拋出異常交給上一級(jí)處理");
            //重新拋出異常
            throw e;
        }
    }
     
    public static void printFile(String file) {
        try {
            readFile(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    public static void main(String[] args) {
        printFile("D:/file");
    }
}

異常的本意是好的,讓我們?cè)噲D修復(fù)程序,但是現(xiàn)實(shí)中我們修復(fù)的幾率很小,我們很多時(shí)候就是用它來(lái)記錄出錯(cuò)的信息。如果你厭倦了不停的處理異常,重新拋出異常對(duì)你來(lái)說(shuō)可能是一個(gè)很好的解脫。原封不動(dòng)的把這個(gè)異常拋給上一級(jí),拋給調(diào)用這個(gè)方法的人,讓他來(lái)費(fèi)腦筋吧。這樣看來(lái),java異常(當(dāng)然指的是受檢異常)又給我們平添很多麻煩,盡管它的出發(fā)點(diǎn)是好的。

例3. 異常鏈的使用及異常丟失

定義三個(gè)異常類:ExceptionA,ExceptionB,ExceptionC

public class ExceptionA extends Exception {
    public ExceptionA(String str) {
        super();
    }
}
 
public class ExceptionB extends ExceptionA {
 
    public ExceptionB(String str) {
        super(str);
    }
}
 
public class ExceptionC extends ExceptionA {
    public ExceptionC(String str) {
        super(str);
    }
}

異常丟失的情況:

public class NeverCaught {
    static void f() throws ExceptionB{
        throw new ExceptionB("exception b");
    }
 
    static void g() throws ExceptionC {
        try {
            f();
        } catch (ExceptionB e) {
            ExceptionC c = new ExceptionC("exception a");
            throw c;
        }
    }
 
    public static void main(String[] args) {
            try {
                g();
            } catch (ExceptionC e) {
                e.printStackTrace();
            }
    }
 
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:19)
*/

為什么只是打印出來(lái)了ExceptionC而沒(méi)有打印出ExceptionB呢?這個(gè)還是自己分析一下吧!

上面的情況相當(dāng)于少了一種異常,這在我們排錯(cuò)的過(guò)程中非常的不利。那我們遇到上面的情況應(yīng)該怎么辦呢?這就是異常鏈的用武之地:保存異常信息,在拋出另外一個(gè)異常的同時(shí)不丟失原來(lái)的異常。

public class NeverCaught {
    static void f() throws ExceptionB{
        throw new ExceptionB("exception b");
    }
 
    static void g() throws ExceptionC {
        try {
            f();
        } catch (ExceptionB e) {
            ExceptionC c = new ExceptionC("exception a");
            //異常連
            c.initCause(e);
            throw c;
        }
    }
 
    public static void main(String[] args) {
            try {
                g();
            } catch (ExceptionC e) {
                e.printStackTrace();
            }
    }
 
}
/*
exception.ExceptionC
at exception.NeverCaught.g(NeverCaught.java:12)
at exception.NeverCaught.main(NeverCaught.java:21)
Caused by: exception.ExceptionB
at exception.NeverCaught.f(NeverCaught.java:5)
at exception.NeverCaught.g(NeverCaught.java:10)
... 1 more
*/

這個(gè)異常鏈的特性是所有異常均具備的,因?yàn)檫@個(gè)initCause()方法是從Throwable繼承的。

例4. 清理工作

清理工作對(duì)于我們來(lái)說(shuō)是必不可少的,因?yàn)槿绻恍┫馁Y源的操作,比如IO,JDBC。如果我們用完以后沒(méi)有及時(shí)正確的關(guān)閉,那后果會(huì)很嚴(yán)重,這意味著內(nèi)存泄露。異常的出現(xiàn)要求我們必須設(shè)計(jì)一種機(jī)制不論什么情況下,資源都能及時(shí)正確的清理。這就是finally。

public void readFile(String file) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file)));
            // do some other work
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

例子非常的簡(jiǎn)單,是一個(gè)讀取文件的例子。這樣的例子在JDBC操作中也非常的常見(jiàn)。(所以,我覺(jué)得對(duì)于資源的及時(shí)正確清理是一個(gè)程序員的基本素質(zhì)之一。)

Try...finally結(jié)構(gòu)也是保證資源正確關(guān)閉的一個(gè)手段。如果你不清楚代碼執(zhí)行過(guò)程中會(huì)發(fā)生什么異常情況會(huì)導(dǎo)致資源不能得到清理,那么你就用try對(duì)這段"可疑"代碼進(jìn)行包裝,然后在finally中進(jìn)行資源的清理。舉一個(gè)例子:

public void readFile() {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("file")));
            // do some other work
         
            //close reader
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }

我們注意一下這個(gè)方法和上一個(gè)方法的區(qū)別,下一個(gè)人可能習(xí)慣更好一點(diǎn),及早的關(guān)閉reader。但是往往事與愿違,因?yàn)樵趓eader.close()以前異常隨時(shí)可能發(fā)生,這樣的代碼結(jié)構(gòu)不能預(yù)防任何異常的出現(xiàn)。因?yàn)槌绦驎?huì)在異常出現(xiàn)的地方跳出,后面的代碼不能執(zhí)行(這在上面應(yīng)經(jīng)用實(shí)例證明過(guò))。這時(shí)我們就可以用try...finally來(lái)改造:

public void readFile() {
        BufferedReader reader = null;
        try {
            try {
                reader = new BufferedReader(new InputStreamReader(
                        new FileInputStream("file")));
                // do some other work
 
                // close reader
            } finally {
                reader.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

及早的關(guān)閉資源是一種良好的行為,因?yàn)闀r(shí)間越長(zhǎng)你忘記關(guān)閉的可能性越大。這樣在配合上try...finally就保證萬(wàn)無(wú)一失了(不要嫌麻煩,java就是這么中規(guī)中矩)。

再說(shuō)一種情況,假如我想在構(gòu)造方法中打開(kāi)一個(gè)文件或者創(chuàng)建一個(gè)JDBC連接,因?yàn)槲覀円谄渌姆椒ㄖ惺褂眠@個(gè)資源,所以不能在構(gòu)造方法中及早的將這個(gè)資源關(guān)閉。那我們是不是就沒(méi)轍了呢?答案是否定的??匆幌孪旅娴睦樱?/p>

public class ResourceInConstructor {
    BufferedReader reader = null;
    public ResourceInConstructor() {
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream("")));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
     
    public void readFile() {
        try {
            while(reader.readLine()!=null) {
                //do some work
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
     
    public void dispose() {
        try {
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

這一部分講的多了一點(diǎn),但是異常確實(shí)是看起來(lái)容易用起來(lái)難的東西呀,java中還是有好多的東西需要深挖的。

四. 異常的誤用

對(duì)于異常的誤用著實(shí)很常見(jiàn),上一部分中已經(jīng)列舉了幾個(gè),大家仔細(xì)的看一下。下面再說(shuō)兩個(gè)其他的。

例1. 用一個(gè)Exception來(lái)捕捉所有的異常,頗有"一夫當(dāng)關(guān)萬(wàn)夫莫開(kāi)"的氣魄。不過(guò)這也是最傻的行為。

public void readFile(String file) {
        BufferedReader reader = null;
        Connection conn = null;
        try {
            reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(file)));
            // do some other work
             
            conn = DriverManager.getConnection("");
            //...
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

從異常角度來(lái)說(shuō)這樣嚴(yán)格的程序確實(shí)是萬(wàn)無(wú)一失,所有的異常都能捕獲。但是站在編程人員的角度,萬(wàn)一這個(gè)程序出錯(cuò)了我們?cè)撊绾畏直媸堑降资悄且鸬哪兀琁O還是JDBC...所以,這種寫(xiě)法很值得當(dāng)做一個(gè)反例。大家不要以為這種做法很幼稚,傻子才會(huì)做。我在公司實(shí)習(xí)時(shí)確實(shí)看見(jiàn)了類似的情況:只不過(guò)是人家沒(méi)有用Exception而是用了Throwable。

例2.?這里就不舉例子了,上面的程序都是反例。異常是程序處理意外情況的機(jī)制,當(dāng)程序發(fā)生意外時(shí),我們需要盡可能多的得到意外的信息,包括發(fā)生的位置,描述,原因等等。

這些都是我們解決問(wèn)題的線索。但是上面的例子都只是簡(jiǎn)單的printStackTrace()。如果我們自己寫(xiě)代碼,就要盡可能多的對(duì)這個(gè)異常進(jìn)行描述。比如說(shuō)為什么會(huì)出現(xiàn)這個(gè)異常,什么情況下會(huì)發(fā)生這個(gè)異常。如果傳入方法的參數(shù)不正確,告知什么樣的參數(shù)是合法的參數(shù),或者給出一個(gè)sample。

例3.?將try?block寫(xiě)的簡(jiǎn)短,不要所有的東西都扔在這里,我們盡可能的分析出到底哪幾行程序可能出現(xiàn)異常,只是對(duì)可能出現(xiàn)異常的代碼進(jìn)行try。盡量為每一個(gè)異常寫(xiě)一個(gè)try...catch,避免異常丟失。

更多java知識(shí)請(qǐng)關(guān)注java基礎(chǔ)教程欄目。

以上是你必須了解的java中的異常的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本站聲明
本文內(nèi)容由網(wǎng)友自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,本站不承擔(dān)相應(yīng)法律責(zé)任。如您發(fā)現(xiàn)有涉嫌抄襲侵權(quán)的內(nèi)容,請(qǐng)聯(lián)系admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費(fèi)脫衣服圖片

Undresser.AI Undress

Undresser.AI Undress

人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用于從照片中去除衣服的在線人工智能工具。

Clothoff.io

Clothoff.io

AI脫衣機(jī)

Video Face Swap

Video Face Swap

使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費(fèi)的代碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級(jí)代碼編輯軟件(SublimeText3)

熱門(mén)話題

Laravel 教程
1601
29
PHP教程
1502
276
如何使用JDBC處理Java的交易? 如何使用JDBC處理Java的交易? Aug 02, 2025 pm 12:29 PM

要正確處理JDBC事務(wù),必須先關(guān)閉自動(dòng)提交模式,再執(zhí)行多個(gè)操作,最后根據(jù)結(jié)果提交或回滾;1.調(diào)用conn.setAutoCommit(false)以開(kāi)始事務(wù);2.執(zhí)行多個(gè)SQL操作,如INSERT和UPDATE;3.若所有操作成功則調(diào)用conn.commit(),若發(fā)生異常則調(diào)用conn.rollback()確保數(shù)據(jù)一致性;同時(shí)應(yīng)使用try-with-resources管理資源,妥善處理異常并關(guān)閉連接,避免連接泄漏;此外建議使用連接池、設(shè)置保存點(diǎn)實(shí)現(xiàn)部分回滾,并保持事務(wù)盡可能短以提升性能。

如何使用Java的日歷? 如何使用Java的日歷? Aug 02, 2025 am 02:38 AM

使用java.time包中的類替代舊的Date和Calendar類;2.通過(guò)LocalDate、LocalDateTime和LocalTime獲取當(dāng)前日期時(shí)間;3.使用of()方法創(chuàng)建特定日期時(shí)間;4.利用plus/minus方法不可變地增減時(shí)間;5.使用ZonedDateTime和ZoneId處理時(shí)區(qū);6.通過(guò)DateTimeFormatter格式化和解析日期字符串;7.必要時(shí)通過(guò)Instant與舊日期類型兼容;現(xiàn)代Java中日期處理應(yīng)優(yōu)先使用java.timeAPI,它提供了清晰、不可變且線

比較Java框架:Spring Boot vs Quarkus vs Micronaut 比較Java框架:Spring Boot vs Quarkus vs Micronaut Aug 04, 2025 pm 12:48 PM

前形式攝取,quarkusandmicronautleaddueTocile timeProcessingandGraalvSupport,withquarkusoftenpernperforminglightbetterine nosserless notelless centarios.2。

了解網(wǎng)絡(luò)端口和防火墻 了解網(wǎng)絡(luò)端口和防火墻 Aug 01, 2025 am 06:40 AM

NetworkPortSandFireWallsworkTogetHertoEnableCommunication whereSeringSecurity.1.NetWorkPortSareVirtualendPointSnumbered0-655 35,with-Well-with-Newonportslike80(HTTP),443(https),22(SSH)和25(smtp)sindiessingspefificservices.2.portsoperateervertcp(可靠,c

垃圾收集如何在Java工作? 垃圾收集如何在Java工作? Aug 02, 2025 pm 01:55 PM

Java的垃圾回收(GC)是自動(dòng)管理內(nèi)存的機(jī)制,通過(guò)回收不可達(dá)對(duì)象釋放堆內(nèi)存,減少內(nèi)存泄漏風(fēng)險(xiǎn)。1.GC從根對(duì)象(如棧變量、活動(dòng)線程、靜態(tài)字段等)出發(fā)判斷對(duì)象可達(dá)性,無(wú)法到達(dá)的對(duì)象被標(biāo)記為垃圾。2.基于標(biāo)記-清除算法,標(biāo)記所有可達(dá)對(duì)象,清除未標(biāo)記對(duì)象。3.采用分代收集策略:新生代(Eden、S0、S1)頻繁執(zhí)行MinorGC;老年代執(zhí)行較少但耗時(shí)較長(zhǎng)的MajorGC;Metaspace存儲(chǔ)類元數(shù)據(jù)。4.JVM提供多種GC器:SerialGC適用于小型應(yīng)用;ParallelGC提升吞吐量;CMS降

比較Java構(gòu)建工具:Maven vs. Gradle 比較Java構(gòu)建工具:Maven vs. Gradle Aug 03, 2025 pm 01:36 PM

Gradleisthebetterchoiceformostnewprojectsduetoitssuperiorflexibility,performance,andmoderntoolingsupport.1.Gradle’sGroovy/KotlinDSLismoreconciseandexpressivethanMaven’sverboseXML.2.GradleoutperformsMaveninbuildspeedwithincrementalcompilation,buildcac

以身作則,解釋說(shuō)明 以身作則,解釋說(shuō)明 Aug 02, 2025 am 06:26 AM

defer用于在函數(shù)返回前執(zhí)行指定操作,如清理資源;參數(shù)在defer時(shí)立即求值,函數(shù)按后進(jìn)先出(LIFO)順序執(zhí)行;1.多個(gè)defer按聲明逆序執(zhí)行;2.常用于文件關(guān)閉等安全清理;3.可修改命名返回值;4.即使發(fā)生panic也會(huì)執(zhí)行,適合用于recover;5.避免在循環(huán)中濫用defer,防止資源泄漏;正確使用可提升代碼安全性和可讀性。

使用HTML'輸入類型”作為用戶數(shù)據(jù) 使用HTML'輸入類型”作為用戶數(shù)據(jù) Aug 03, 2025 am 11:07 AM

選擇合適的HTMLinput類型能提升數(shù)據(jù)準(zhǔn)確性、增強(qiáng)用戶體驗(yàn)并提高可用性。1.根據(jù)數(shù)據(jù)類型選用對(duì)應(yīng)input類型,如text、email、tel、number和date,可實(shí)現(xiàn)自動(dòng)校驗(yàn)和適配鍵盤(pán);2.利用HTML5新增類型如url、color、range和search,可提供更直觀的交互方式;3.配合使用placeholder和required屬性,可提升表單填寫(xiě)效率和正確率,但需注意placeholder不能替代label。

See all articles