20 Years Of Java Deprecation

I’m really not sure how I stumbled across this link, but it was a while ago and I put a reminder in my diary so I’d remember the twentieth anniversary of the unveiling of the @deprecated javadoc tag. As such I thought some reflections on this would make an interesting blog entry.

When Java was first launched it came with a [fairly limited] set of class libraries. If you search on the Oracle website you will find archived copies of the JDK going all the way back to JDK 1.1, but it seems they no longer maintain a link to JDK 1.0. After some digging through the vast sea of data I’ve collected over the last twenty-plus years, I found a copy of the JDK 1.0.2 source code. Having unpacked it I found that there were 215 classes and interfaces in the standard class libraries (compare that to over 4,500 in JDK 8!). For your amusement, the table below shows the number of public APIs from each major JDK release (Caveat emptor: I did this with a combination of grep and other commands using mostly the javadocs so I don’t guarantee that it’s 100% accurate) 

  JDK Release  

  Public classes/interfaces  

1.0.2

215

1.1

477

1.2

1758

1.3

2104

1.4

2991

5.0

3550

6

4068

7

4299

8

4518

9

4761

Next, using the JDK 1.1 documentation I did a grep for deprecated. This showed that 37 classes/interfaces had one or more deprecated methods. The winner, by quite a long way, was java.awt.Component. No less than 37 methods of the original 129 were deprecated; some significant change of heart over the design of that one.

As of JDK 1.2, things get a lot simpler for analysing deprecation, as the documentation includes a deprecated-list.html file. Of course, the types of things being deprecated changed over time, so in JDK 9 we now have a list of deprecated interfaces, classes, exceptions, annotation types, fields, methods, constructors and annotation element types.

Using more tools from my UNIX command line toolbox I was able to produce the following summary of cumulative deprecation for all major releases of the JDK.

 JDK 

 Interfaces 

 Classes 

 Exceptions 

 Fields 

 Methods 

 Constructors 

1.1

0

2

0

0

133

7

1.2

5

11

4

15

239

16

1.3

5

12

4

49

262

17

1.4

8

18

4

49

279

18

5

16

21

4

52

319

20

6

17

21

4

54

337

20

7

17

21

4

58

343

20

8

18

23

5

64

358

20

9

28

39

13

73

365

38

(Three annotation types and one annotation element type were deprecated in JDK 6 and nothing has changed since so I didn’t include those in the table).

We can produce some simple bar charts for this data to make it a little easier to see the changes.

classes interfaces exceptions fields JDK deprecated methods constructors

Several points stick out here:

  • Classes: A fair jump in JDK 1.2, but the biggest jump for JDK 9.
  • Interfaces: JDK 5.0 deprecated quite a few, but again the biggest jump was in JDK 9.
  • Exceptions: JDK 9 wins again
  • Fields: Not so much change in JDK 9 here, but a big jump in JDK 1.3
  • Methods: Looks like JDK 1.2 got the biggest jump here, with a gradual increase afterwards.
  • Constructors: JDK 1.2 and JDK 9 win again.

I think what you can see here is that the introduction of modularity with Project Jigsaw in the JDK is having a significant impact in terms of elements being deprecated.

This brings us to another interesting point concerning deprecation in the JDK. With the current release, JDK 8, a grand total of 492 elements have been deprecated. How many of these have actually been removed? The answer is simple: none. This is where deprecation becomes more contentious. An obvious question is, “If no deprecated elements ever get removed, what’s the point of deprecating them?” The answer is really about balancing the evolution of the API (being able to remove parts as well as add them) with not breaking backwards compatibility. The compiler can warn developers when they are using deprecated APIs and the documentation can lead them to (hopefully) the new, improved alternative. This can be a gradual process with developers able to plan their code migration without their applications suddenly no longer compiling or running with a new release of the Java platform.

Until now. In JDK 9 some previously deprecated APIs will actually be removed. The number is very small; only six methods are being removed. Another question springs to mind, which is “What have these six methods done that is so bad that they finally get removed?” To understand this you need to look at JDK Enhancement Proposal (JEP) 162, which was included in JDK 8. This lists the six offending methods as:

  • util.logging.LogManager.addPropertyChangeListener
  • util.logging.LogManager.removePropertyChangeListener
  • util.jar.Pack200.Packer.addPropertyChangeListener
  • util.jar.Pack200.Packer.removePropertyChangeListener
  • util.jar.Pack200.Unpacker.addPropertyChangeListener
  • util.jar.Pack200.Unpacker.removePropertyChangeListener

There’s not really a clear explanation for why these six need to be removed other than, “The dependency on PropertyChangeListener creates a significant impediment to future modularization of the Java platform.” I assume that somehow these six APIs caused major problems for the module design for JDK 9.

Other than the number of elements being deprecated the only significant change to deprecation in Java until JDK 9 was the introduction of the @Deprecated annotation in JDK 5.0 (which was when annotations were introduced). Whereas prior to JDK 5.0 the compiler was under no obligation to take any notice of @deprecated javadoc tags, now the Java Language Specification (section 9.6.4.6) mandates that the compiler must issue a warning unless something like @SuppressWarnings(“deprecation”) is used.

JDK 9 will introduce some changes to deprecation, which have been documented in JEP 277: Enhanced Deprecation. To start with the @Deprecated annotation type will have two methods added to it:

  1. forRemoval(), returning a boolean. This will indicate whether the element will ever be removed at some point in the future. Certain elements, although marked as deprecated, will never be removed.
  2. since(), returning a String. This will return a value indicating the version of the JDK when this element was deprecated.

Since the @Deprecated annotation has RUNTIME retention this information can be used when an application is running as well as when it is compiled. More detailed information can be provided to developers at compile time using the @deprecated javadoc tag. JEP 277 considers it to be an error to have only the @deprecated tag or @Deprecated annotation but not both (which seems sensible).

JEP 277 also contains a list of some proposed changes to APIs that will have modifications in terms of the @Deprecated annotation. I must admit I find this list rather confusing, as the JEP says the list is not exhaustive and also states that not all the changes may make it into JDK 9. I would have thought that by this stage of JDK 9 development this list would be definitive by now. Probably the most surprising ‘suggestion’ on this list is that the java.awt.Component show() and hide() methods are being given a reprieve and will have the @Deprecated annotation removed!

There are also ideas for future work on deprecation, with ideas like enabling logging and being able to record stack traces for running applications. We’ll have to wait for JDK 10 to see which of these ideas are adopted.

Deprecation is a very useful tool for API design and evolution and with the changes in JDK 9, we should see clearer information to help developers understand what changes they need to make to their code and in a timely manner to avoid problems of compatibility with newer versions of the JDK.

In what might seem like something of an oxymoron, after twenty years deprecation is alive and well in Java!

 

 

 

 

 

© Azul Systems, Inc. 2017 All rights reserved.