Preface
There are more and more Android developers using Kotlin now.
This language went from being ignored at the beginning to becoming a first-class language for Android development, and then to Kotlin First, which Google announced. Kotlin is being accepted and recognized by more and more developers.
Many developers who learn Kotlin have learned Java before, and Kotlin itself is a JVM-based language, so it is inevitable that it needs to be compared with Java frequently.
In the eyes of developers familiar with Java, some people like Kotlin's many features, while others don't. But even those who don’t like can hardly escape the law of true fragrance once they are familiar with Kotlin.
Today I want to talk to you about the topic, which is a very controversial feature of Kotlin in the early days: the Checked Exception mechanism.
Because Kotlin cancels Checked Exception, this is completely unacceptable to many Java developers, and may be the reason why many Java supporters refuse to use Kotlin. But Kotlin has been fully reincarnated by Google for more than two years and has developed thousands of Android applications. You will find that even without Checked Exception, Kotlin does not have more problems with programs written by it than Java, so the necessity for Checked Exception in programming languages may not be as high as many people think.
Of course, in this article, I cannot give a conclusion to prove who is right and who is wrong. I will talk to you more about my own views and personal experiences, and also quote the authoritative views of some big shots.
Also, there is never a correct answer to this question, because there is no best programming language in the world (except PHP). Each programming language has its own set of theories and logic when choosing different processing methods. So instead of debating whether the Checked Exception mechanism in Java is redundant, it is better to argue why the Checked Exception mechanism in Kotlin is reasonable.
So, let's start with what is Checked Exception.
What is Checked Exception?
Checked Exception, referred to as CE. It is a mechanism introduced by programming languages to ensure that programs can handle and catch exceptions better.
Specifically, when a method calls another interface that may throw an exception, either capture the exception or throw the exception and hand it over to the previous layer for capture.
Friends who are familiar with the Java language must be familiar with this mechanism, because we write programs under the influence of this mechanism almost every day.
Observe the following code:
public void readFromFile(File file) { FileInputStream in = null; BufferedReader reader = null; StringBuilder content = new StringBuilder(); try { in = new FileInputStream(file); reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while ((line = ()) != null) { (line); } } catch (IOException e) { (); } finally { if (reader != null) { try { (); } catch (IOException e) { (); } } } }
This code should be very familiar to every Java programmer. This is a piece of code for Java file streaming operations.
When we perform file flow operations, various potential exceptions may occur, so these exceptions must be caught or thrown, otherwise the program will not be able to compile and pass. This is Java's Checked Exception mechanism.
With Checked Exception, we can ensure that our program will not have some hidden potential exceptions, otherwise, these exceptions will be like a time bomb and may detonate our program at any time.
From this point of view, Checked Exception is a very necessary mechanism.
Why is there no CE in Kotlin?
There is no Checked Exception mechanism in Kotlin, which means that when we use Kotlin for the above file flow operations, we can compile and pass normally even if we do not catch or throw exceptions.
Do developers familiar with Java feel that it is so serious and insecure?
So let’s try to analyze and think about why there is no Checked Exception in Kotlin.
When I was studying Kotlin, I found that this language referenced some of the best programming practices in the industry in many design aspects.
For example, the book "Effective Java" mentioned that if a class is not designed specifically for inheritance, then we should declare it as final so that it cannot be inherited.
In Kotlin, a class is not inheritable by default, unless we actively declare it as open.
There are many similar examples.
Therefore, Kotlin's cancellation of Checked Exception is definitely not a decision by casually, but has many theoretical basis to support it.
For example, Bruce Eckel, the author of "Thinking in Java", once publicly stated that Checked Exception in the Java language is a wrong decision and Java should remove it. Anders Hejlsberg, the father of C#, also agrees with this view, so there is no Checked Exception in C#.
So what exactly is the problem with the Checked Exception mechanism that most of us Java developers think is very necessary?
These bigwigs have given many examples of reasons, but I personally think the main reason is actually one: trouble.
Although the Checked Exception mechanism improves the security of programming languages, it sometimes makes us quite crazy when writing code.
Due to the existence of the Checked Exception mechanism, we must process some code that may have potential exceptions. There are only two ways to deal with it: either use the try catch code block to catch the exception, or use the throws keyword to throw the exception.
Taking the file stream operation just now as an example, we used try catch code blocks twice to perform potential exception capture, but in fact it is more just to satisfy the compiler:
public void readFromFile(File file) { BufferedReader reader = null; try { ... } catch (IOException e) { (); } finally { if (reader != null) { try { (); } catch (IOException e) { (); } } } }
This code is the most standard and standardized way to write in Java, but you will find that almost no one can write any meaningful logical processing in catch. Usually, they just print out exception information to inform the stream of exceptions. So what should I do if an exception occurs in a stream? No one knows what to do, theoretically streams should always work properly.
Think about it, is the try catch you added when closing the file stream just to allow the compile to pass? Have you done any meaningful logical processing in the exception catch of close?
The existence of the Checked Exception mechanism forces us to handle these uncaught exceptions, even if we explicitly don't want to handle them.
The design idea of this mechanism is good in itself, but it also indirectly creates a lot of cramming code, just to satisfy the compiler's programming, resulting in many meaningless try catch statements being written, making the project code seem more bloated.
So what if we choose not to catch the exception, but throw the exception upward? It turns out that this may not be a particularly good idea, either.
Most Java programmers should have used reflection APIs. It is a bit annoying when writing reflection code, that is, its API will throw a lot of exceptions:
Object reflect(Object object, String className, String methodName, Object[] parameters, Class<?>[] parameterTypes) throws SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException { Class<?> objectClass = (className); Method method = (methodName, parameterTypes); return (object, parameters); }
Here I just wrote the simplest reflection code, and there are 6 exceptions waiting for me to deal with. I haven't fully understood what each exception means. Instead of writing a lot of try catch code myself, it's better to throw all exceptions directly to the previous layer, so that the code will look a little refreshing.
This is what you think, and the people on the previous level think so. What's more excessive is that they may add a little more other exceptions to continue throwing up on the basis of your throwing exception.
According to the information I have read, some projects need to even catch more than 80 exceptions after such layers of accumulation. I believe that the person who calls this interface must be cursing in his heart. Do you think that in this case, he can still patiently handle every exception type carefully? It is absolutely impossible. There is a high probability that he will only catch a top-level Exception and include all exceptions, thus completely making the Checked Exception mechanism meaningless. Or, he might add another fire to the current exception throw chain to contribute to throwing 100 exceptions. . .
Finally, we can see that the original design intention of Java's Checked Exception mechanism is indeed good and advanced, but it has high coding specification requirements for programmers. The designer of each layer of method should be able to clearly distinguish which exceptions should be caught internally and which exceptions should be thrown upward, so that the exception chain of the entire method call stack is within a reasonable and controllable range.
However, the regrettable reality is that most programmers actually cannot do this. The abuse and lazy use of CE mechanisms are widely present, and they completely fail to achieve the expected effect of Java itself designing this mechanism. This is also the reason why Kotlin cancels the Checked Exception.
Will there be no problem without CE?
Many Java programmers are more worried about this. Kotlin canceled the Checked Exception mechanism, so that it will not cause my program to become very dangerous? Whenever I call a method, I have no idea what exception this method might throw.
First of all, this question has been answered at the beginning. After more than two years of practice, it was found that even without Checked Exception, the programs developed by Kotlin did not have more exceptions than those developed by Java. On the contrary, Kotlin programs reduce a lot of exceptions, because Kotlin adds the function of handling null pointer exceptions during compilation (null pointers have always ranked first in the crash rate rankings of various languages).
So as for why canceling Checked Exception will not be the reason for more exceptions to the program, I would like to discuss it in the following points.
First, Kotlin does not prevent you from catching potential exceptions, it just does not force you to catching them.
When an experienced programmer writes a program, it is mostly clear what is most likely to occur. For example, I am writing network request code. Due to the instability of the network, the request failure is very likely to happen. So even without a Checked Exception, most programmers know that a try catch should be added here to prevent the program from crashing due to failure of the network request.
In addition, when you are not sure whether a method will be thrown by calling it, you can always make sure by opening this method and observing its throw declaration. Regardless of whether you have the source code of this class or not, you can see which exceptions it throws in each method:
public class FileInputStream extends InputStream { public FileInputStream(File file) throws FileNotFoundException { throw new RuntimeException("Stub!"); } public int read(byte[] b, int off, int len) throws IOException { throw new RuntimeException("Stub!"); } public void close() throws IOException { throw new RuntimeException("Stub!"); } ... }
Then when you feel that you need to catch this exception, you can still write Kotlin code in the way you catch exceptions in Java before, but without the mandatory requirements, you can freely choose whether to capture and throw.
Second, most methods actually do not throw exceptions.
This is a fact, otherwise you will never fall in love with the Checked Exception mechanism, but will curse it every day.
Just imagine, if every line of code you write and every method you call must be caught by trying catch, do you have the intention to throw the keyboard?
The situation I mentioned really has a very typical example in Java, which is the() method. Since the() method will throw an InterruptedException, every time we call this method, we must use try catch to catch:
public class Main { public void test() { // do something before try { (1000); } catch (InterruptedException e) { (); } // do something after } }
This is also the reason why I don’t like this method very much. It’s just one word to use: annoying.
In fact, most Java programmers may not even know why they want to catch this exception, they only know that the compiler reminds me that I must catch it.
The reason why we need to catch InterruptedException when calling the() method is because if we interrupt the sleeping thread in another thread during the current thread (called the() method), the sleep() method will end the sleep and throw an InterruptedException. This kind of operation is very rare, but due to the existence of Checked Exception, each of us needs to pay for this rare operation: that is, every time we call the() method, we have to write a long try catch code.
And in Kotlin, you no longer hate using the() method, because without the Checked Exception, the code becomes refreshing:
class Main { fun test() { // do something before (1000) // do something after } }
Third, Java with Checked Exception is not that safe either.
Some people think that with the Checked Exception mechanism in Java, you will feel relieved of every method you call because you know what exception it will throw. If there is no Checked Exception, you will feel unsure of calling any method.
So does this statement make sense? Obviously this is not true. Otherwise, your Java program should never crash.
In fact, Java divides all exception types into two categories: checked exception and unchecked exception. Only checked exceptions will be subject to the Checked Exception mechanism. Unchecked exceptions will not force you to catch or throw exceptions.
For example, NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException are all exceptions that are not checked, so even if there are exception risks such as null pointers and arrays that are out of bounds in the method you call, the Checked Exception mechanism will not require you to capture or throw.
It can be seen that even if Java has the Checked Exception mechanism, it cannot guarantee you that every method you call is safe, and I think exceptions such as null pointers and array out-of-bounds are far more common than exceptions such as InterruptedException, but Java does not protect this.
As for how Java divides which exceptions belong to checked exceptions and which ones belong to unchecked exceptions, I don't know much about this. The Java design team must have its own set of theoretical basis, but this set of theoretical basis does not seem to be recognized by designers in other languages.
Therefore, you can probably understand that Kotlin further simplifies the exception type, classifying all exceptions as unchecked exceptions, and that's it.
in conclusion
So, what is the final conclusion?
Unfortunately, there is no conclusion. Just as everything has its own diversity, there is no unified conclusion on the question of Checked Exception.
It is not wrong to have the Checked Exception mechanism in Java, and it is not wrong to cancel the Checked Exception mechanism in Kotlin. I think this is probably the conclusion you can draw after reading this article.
However, I hope that from now on, when using Kotlin to program programs, you will no longer be confused about whether there is a Checked Exception.
Summarize
This is the introduction to this article about the Checked Exception mechanism in Kotlin. For more information about the Checked Exception mechanism of Kotlin, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!