views:

711

answers:

12

I recently started learning Java and found it very strange that every Java class must be declared in a separate file. I am a C# programmer and C# doesn't enforce any such restriction.

Why does Java do this? Were there any design consideration?

Edit (based on few answers):

Why is Java not removing this restriction now in the age of IDEs? This will not break any existing code (or will it?).

+4  A: 

It's just to avoid confusion in the sense that Java was created with simplicity in mind from the perspective of the developer. Your "primary" classes are your public classes and they are easy to find (by a human) if they are in a file with the same name and in a directory specified by the class's package.

You must recall that the Java language was developed in the mid-90s, in the days before IDEs made code navigation and searching a breeze.

oxbow_lakes
easier to find for whom? The compiler.
Sandbox
No - I just mean easier for the user - I've modified my answer
oxbow_lakes
IDEs have been around since the mid 80s (at least) - ever heard of Turbo Pascal?
anon
IF the decision to put each public class in a file was JUST for 'easy to find (by a human)..' a newbie like me can say it wasn't a correct decision
Sandbox
Yes - I know; I started using Smalltalk which has been around for a *long* time and comes with an IDE by design. But Java was created to be more like C/C++ (for better or worse) and I think my point still stands
oxbow_lakes
@oxbow Neither C nor C++ has any mapping between file name and class. And IDEs have been available for both for years - I remember using the DeSmet C IDE in the mid 80s
anon
Java? Simplicity in mind for the developer? It doesn't look like that to me.
Ionuț G. Stan
@Neil - sorry, I didn't put that very well. I wasn't implying that C or C++ had one class/file. I was implying that they didn't have extensive IDEs at that time. I may be wrong about this but the early Java IDEs (JBuilder for example) had appalling code navigation. I for one am glad that they chose a single public class per file.
oxbow_lakes
@oxbow_lakes Look at http://stackoverflow.com/questions/1318712/why-is-each-public-class-in-a-separate-file/1318752#1318752. Looks like it was for easier to find for compiler and not for human
Sandbox
@Sandbox. Very interesting, though I'm not sure about your implication that decisions made solely for the benefit of humans are not made on a good basis.
oxbow_lakes
@oxbow_lakes Didn't really intend to imply that. Just that I couldn't digest that the decision was made so as to make it easier to find files for humans.
Sandbox
+2  A: 

It is technically legal to have multiple Java top level classes in one file. However this is considered to be bad practice, and many Java tools (including IDEs) do not work if you do this.

The JLS says this:

When packages are stored in a file system (§7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:

  • The type is referred to by code in other compilation units of the package in which the type is declared.
  • The type is declared public (and therefore is potentially accessible from code in other packages).

Note the use of may in the JLS text. This says that a compiler may reject this as invalid, or it may not. That is not a good situation if you are trying to build your Java code to be portable at the source code level. Thus, even if multiple classes in one source file works on your development platform, it is bad practice to do this.

My understanding is that this "permission to reject" is a design decision that is intended in part to make it easier to implement Java on a wider range of platforms. If (conversely) the JLS required all compilers to support source files containing multiple classes, there would be conceptual issues implementing Java on a platform which wasn't file-system based.

In practice, seasoned Java developers don't miss being able to do this at all. Modularization and information hiding are better done using an appropriate combination of packages, class access modifiers and inner or nested classes.

Stephen C
The JLS says nothing (normative) about the subject.
Tom Hawtin - tackline
@Tom: really? Did you see my edit?
Stephen C
Portable - for byte code this should be the same regardless of compiler. For source you would have some explaining to dó if it fails with javac
Thorbjørn Ravn Andersen
@Thorbjorn: I meant at the source code level. I'll edit my answer to make this crystal clear.
Stephen C
+17  A: 

According to the Java Language Specification, Third Edition:

This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.

Emphasis is mine.

It seems like basically they wanted to translate the OS's directory separator into dots for namespaces, and vice versa.

So yes, it was a design consideration of some sort.

Mark Rushakoff
Does anyone have experience of using Java on platforms that don't have tree-structured directores? Perhaps someone that works on something like VM/CMS (or maybe it does have tree structures now - last time I used it was about 1988) could comment?
anon
Or I would say when they develop Java they are lazy :)
Jonathan Shepherd
@Neil: Visual Age didn't store its files in the file system, but in a (proprietary) Database instead. It still presented your classes hierarchically, due to the package system however.
Joachim Sauer
You know, from the effect this consideration had, I think it does totally enforce programmers to rethink about coupling code. People who DON'T think it's a good idea to write their classes, as in at least one-file-per-public-class-basis, obviously haven't been on large projects long enough to get fed up with rereading large code files just to change "that small thing" (or are ignorant about it). It's not about lazyness, it's about not mundanely repeating yourself
Spoike
+3  A: 

If a class is only used by one other class, make it a private inner class. This way you have your multiple classes in a file.

If a class is used by multiple other classes, which of these classes would you put into the same file? All three? You would end up having all your classes in a single file...

Zed
+24  A: 

I have just taken a C# solution and did just this (remove any file that had multiple public classes in them) and broke them out to individual files and this has made life much easier.

If you have multiple public classes in a file you have a few issues:

  1. What do you name the file? One of the public classes? Another name? People have enough issues around poor solution code organization and file naming conventions to have one extra issue.

  2. Also, when you are browsing the file / project explorer its good that things aren't hidden. For example you see one file and drill down and there are 200 classes all mushed together. If you have one file one class, you can organize your tests better and get a feel for the structure and complexity of a solution.

I think Java got this right.

ooo
exactly. More classes within the same file is a nightmare. It just complicates life, I don't see any advantage in doing so.
Juri
I totally agree.
javashlook
Yeah, it makes total sense to me. Not just because I'm a Java programmer, but because it makes the naming scheme just sort of fall into place on its own.
MattC
In C# code 99% of situations where I have several public classes in one file is: one public full-lown class and a few interfaces, enums or delegates this class uses.
Ula Krukar
On the other hand, I still think decision should be left to the developer, not enforced.
Ula Krukar
maybe, but flexibility is not always the best thing. More and more we are seeing the benefits of solutions built on convention over configuration.
ooo
+2  A: 

Why is java not removing this restriction now in the age of IDEs? This will not break any existing code (or will it?).

Now all code is uniform. When you see a source file you know what to expect. it is same for every project. If java were to remove this convention you have to relearn code structure for every project you work on, where as now you learn it once and apply it everywhere. We should not be trusting IDE's for everything.

Hamza Yerlikaya
404 Restriction not found
280Z28
+1  A: 

Not really an answer to the question but a data point none the less.

I grepped the headers of my personal C++ utilty library (you can get it yourself from here) and almost all of the header files that actually do declare classes (some just declare free functions) declare more than one class. I like to think of myself as a pretty good C++ designer (though the library is a bit of a bodge in places - I'm its only user), so I suggest that for C++ at least, multiple classes in the same file are normal and even good practice.

anon
+1  A: 

It allows for simpler heuristics for going from Foobar.class to Foobar.java.

If Foobar could be in any Java file you have a mapping problem, which may eventually mean you have to do a full scan of all java files to locate the definition of the class.

Personally I have found this to be one of the strange rules that combined result in that Java applications can grow very large and still be sturdy.

Thorbjørn Ravn Andersen
+3  A: 

That's just how the language designers decided to do it. I think the main reason was to optimize the compiler pass-throughs - the compiler does not have to guess or parse through files to locate the public classes. I think it's actually a good thing, it makes the code files much easier to find, and forces you to stay away from putting too much into one file. I also like how Java forces you to put your code files in the same directory structure as the package - that makes it easy to locate any code file.

Andy White
+14  A: 

From Thinking in Java

:

There can be only one public class per compilation unit (file).
The idea is that each compilation unit has a single public interface represented by that public class. It can have as many supporting “friendly” classes as you want. If you have more than one public class inside a compilation unit, the compiler will give you an error message.


From the specification (7.2.6)

When packages are stored in a file system (?7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:

  • The type is referred to by code in other compilation units of the package in which the type is declared.
  • The type is declared public (and therefore is potentially accessible from code in other packages).
  • This restriction implies that there must be at most one such type per compilation unit.
  • This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package; for example, the source code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket, and the corresponding object code would be found in the file Toad.class in the same directory.

In short: it may be about finding classes without having to load everything on your classpath.

Edit: "may choose" seems like it leaves the possibility to not follow that restriction, and the meaning of "may" is probable the one described in RFC 2119 (i.e. "optional")
In practice though, this is enforced in so many platform and relied upon by so many tools and IDE that I do not see any "host system" choosing to not enforce that restriction.


From "Once upon an Oak ..."

It's pretty obvious - like most things are once you know the design reasons - the compiler would have to make an additional pass through all the compilation units (.java files) to figure out what classes were where, and that would make the compilation even slower.

(Note:

the Oak Language Specification for Oak version 0.2 (postcript document): Oak was the original name of what is now commonly known as Java, and this manual is the oldest manual available for Oak (i.e. Java).
For more history on the origins of Java, please have a look at the Green Project and Java(TM) Technology: An Early History
)

VonC
@VonC: Just to be clear, the text that you quoted from the JLS says that a Java platform **may** forbid multiple classes per source file. It does not say that it **must** forbid this. (But you shouldn't do this anyway. If you do, your source code won't compile on some platforms; e.g. in typical IDEs.)
Stephen C
'May' may have a different meaning in standards documents than in natural speech...
EricSchaefer
@Stephen, Eric: I just added a small section about the meaning of "may" in specifications. It is true it does not say "must", but still... it seems enforces in too many place already.
VonC
Thanks for the completeness of the answer, including the historical information about Oak.
Jesper
+1  A: 

There can be many public classes in a single file. However, top-level class per file. There can be as many public inner/nested classes per file as you like.

I think you like this link - http://stackoverflow.com/questions/968347/can-a-java-file-have-more-than-one-class

adatapost
A: 

IMHO, probably the worst design decision in the history of computing was for Java to force the file to class mapping.

I agree, it's not unlike the worst decision ever made in the history of government, and we are all lucky to have survived it: requiring uniform license plates at the rear of each and every vehicle. I admire your sense of proportion, impact and utility. It's mind boggling.

Rick O'Shay