You can like something that you don't think is particularly useful or even productive. I like Brainfuck and Whitespace, but I'd never write code in them unless I was really depressed.
Yeah, not getting his point. Sure, you wouldn't want to work with it, but the reality is that letting go of the idea of writing perfect code helps you just getting it done. It's sickening, but it's a valid point.
Very misleading title for a great article. I will probably point people to this in the future when they ask me why I don't like Java (yet continue to use it).
If I interviewed for a company where a serious interview question was to copy stdin to stdout I'd probably laugh and walk out. Stating the obvious: this company obsesses over the most efficient way to re-invent the wheel... Good luck getting any real work done or learning any career portable skills!
The author made it clear that the question's primary purpose was to see if the applicant could use the system. They assumed, incorrectly as it turned out, that the problem was about as trivial as hello world.
Per the article, this didn't sound like a serious question, but a "get used to the system we use" question. Like a test system implementing a multiple choice exam asking a ridiculously stupid first question to get the user familiar with the interface, like: "Is your name: A. Jtsummers; B. Bob Summers; C. John Doe; D. The Queen of England". And expecting the user to correctly pick their own name.
Have you conducted interviews yourself? It is harder than it seems.
There are a lot of nervous and shy people. Easing them into the process with an 'icebreaker' question gives them a chance to open up for the real questions.
(4) Even if this isn't his attempt, there's genuine depth to even this problem. If you do the obvious
a = get_byte()
while a != EOF:
send_byte(a)
a = get_byte()
There's a surprising amount of work going on behind the scenes that you can dive into discuss how I/O works, when would you do this using blocking vs. non-blocking I/O, when should you do your own buffering or let the language/library do it for you. But it's short enough to get started to get to those points very quickly.
(5) I wouldn't hire/not hire someone based on style alone, but you can get a pretty good feel for it from short programs that actually work. If the tasks or snippets on which you interview are too short to be complete programs, you miss a lot of organisation and "shape of the code" kind of stuff from their style.
(6) Interviews are tough as an interviewee. Professional programmers aren't professional job interviewers and often it can be hard to read their mind to see what they are looking for in a particular question. "It's open ended, take it where you like" usually doesn't mean what it says on the tin. As far as going from "here's a question" to "here's an answer" with little ambiguity this is one of the better FizzBuzz type questions I've seen.
> (3) A surprising number of programmers can't program.
This reminded me of the interview for my first job. I was basically between a rock and a hard place so part of what follows was clearly, in retrospect, a bad sign, but the choice between job and no job but $20k in debt to cover, I took the job.
The shop was a C shop, embedded systems. When I went in to interview I was virtually a shoo-in (just learned I'd misspelled this for years as shoe-in) for the job due to a college classmate already working there and recommending me. The code segment was straightforward. It presented several "implementations" in C of functions to swap the values in two variables. That is:
int x = 10;
int y = 20;
swap(x,y); // after this point x == 20 and y == 10 should be true
void swap(int x, int y) { int t = x; x = y; y = x; }
Now, that obviously won't work in C. One of the implementations was correct, 3 were wrong (like the above snippet). I was asked which were wrong, why they were wrong, which was correct. I answered them all (note: this was a week 2 or 3 programming assignment when I took a course using C as an undergrad, it really seemed obvious to me), and the interviewer was surprised. I was told, "You're the first person to get all these questions correct."
Like I said, warning signs. Alarm bells should have been going off. If the interviewer tells you that, that means that your colleagues couldn't answer those questions. That only occurred to me about 4 weeks later once I'd finished all my reading and project familiarization and was getting into really working with my new peers.
Maybe not reinvent, but you'd damn well better understand how the wheel works or at least be able to deduce it, maybe even be curious about it as an engineering problem. Forget even that somebody's still got to build the wheels of tomorrow (last I checked my car and the car I am likely to buy decades from now still has wheels so I imagine its proper function is still an ongoing engineering issue for somebody), but say you work on a problem and it turns out the root cause of an issue lies in the proverbial wheel - are you going to hem and haw and say that this piece is beneath you? Or are you going to fix the problem?
Wrong. The reason FizzBuzz (as another example) is a widely used interview problem is that it is a middle ground: a problem that won't be a time-waster on competent candidates, but will completely stump idiots.
Given the solutions that people have posted on here which have demonstrable problems, I think it's a pretty good question as an opener. And as someone said already, it gives you a lot of scope for drilling down into the nitty-gritty.
Following up, the main argument is "java doesnt have hashes built in".
Well neither does C, C++ as well. Nor does Scala actually.
There are a lot of good things about Java, namely the JVM, interfaces, great libraries, reflection and code generation, etc, etc. For example libraries like jmock/etc.
That isn't part of the language, that's part of the standard library. Just the same as java, which has a standard hashing function, AND hash table/map.
Ultimately, where does the language end, and the standard library begin? Whats the real difference? Yeah, so C++ and Java don't have built in syntax for hash tables. That's it?
I hate Java, and loved this article. Not what I was expecting. Now excuse me as I have 213 more classes to write each containing about 2 lines of real code.
Some of the things you mentioned I would categorize as non-essential, but putting Lucene and Hadoop into the same category seems unreasonable to me. These tools do solve real world problems and they are absolutely non-superficial. If anything such lists show how versatile is the JVM.
Personally, I like my current mediocre code taskings. There's nothing innovative at all about the programs I'm writing for work, and it's fantastic. It's my mental vacation for a few months (they're not small programs, but they aren't difficult either), staving off the inevitable burnout.
If mediocre code gets the job done faster and it's reasonably maintainable, but you avoid it due to code-idealism, the problem might not lie with the language.
> In Java, you can forget about doing it in the cleanest or the best way, because that is impossible. Whatever you do, however hard you try, the code will come out mediocre, verbose, redundant, and bloated
But I really believe the future of software is affected more by having better programmers rather than having better languages.
Yes, it helps to have cool languages like Julia, Nimrod, Rust, even Scala (which I think is the best statically typed JVM language out there). But I tend to think that a good developer will be good in any language, Haskell, C, Java or LOLCODE.
I think that a good developer "forced" to use Java will find tools that bring out the good parts of the language: Dropwizard, Play framework / Akka, even latest versions of Spring and Java EE are much more convention over configuration and lightweight than before.
They will use Guava and Apache commons to streamline common Java verbosity and bloat.
They'll use Java 8 which allows much more robust and concise syntax to common problems.
But I don't think that the language is the problem. I think that a great developer will be able to tackle any problem with the language itself easily, because the real problem is not how to implement X, but more what is X. Designing the software correctly is the main problem at hand, not how to move input to output. This is what stackoverflow is for.
One last point about this all "I hate/like Java" type of post
1) If you write Java for your day job and hate it, either try to introduce something else (Clojure / Scala / Java 8 / Kotlin)
If you can't introduce any of these then either accept your fate or just quit and find another job. If you can't find another job, then perhaps you deserve to stay and write Java so stop whining, it's not that bad (and one day you'll get to use Java 8).
2) If you don't write java for your day job but as a freelancer - start getting other non-java gigs. Not so many non Java jobs? well, continue to write Java bashing blog posts until people will stop using it I guess...
3) If you don't write Java for your day job or as a freelancer, then just stop complaining about it. There are million of other things (not just programming languages) out there worth complaining about. They can use your writing talent for a better cause.
Only new Java projects would actually use the Java 8 features anytime soon. Existing Java codebases will stick to their Java 6 installation for a long while. It could be years before lambdas are used to any significant degree. Look at how long it took for many Java 1.4 shops to actually upgrade to Java 5, let alone encourage developers to use its features. Even today a lot of places still allow and even encourage use of collections classes without the generics specified.
You can start using Java 8 as soon as you are willing to move. I don't think there are many breaking changes in the new version. Just give it a few months to be really stable. Last week , it took me around ten minutes to move one application from 6 to 7.
"You can start using Java 8 as soon as you are willing to move."
As long as you aren't writing Java code on Android, in which case you're still stuck at Java 6 (with a very small subset of Java 7 features that were added 3 years after Java 7 came out).
Not the fault of the Java language, really, but it is incredibly annoying how unclear Google has been on the future of their dialect of Java post the Oracle lawsuit.
It's worth noting that Android 4.4 does support pretty much all JDK7 features (multicatch / try with resources / etc), finally. I've run into the occasional missing method from some of the newer class libraries, but nothing too serious.
Of course, if this is any indication it'll be several years before its safe to use even JDK7 features considering Android's update trends, let alone JDK8 ...
One worth noting: If existing code is using Proxy.getProxyClass and the Constructor.newInstance method to create a proxy instance, it will fail with IllegalAccessException. RFE 4487672
Why would you ever do that..? If your production code is using those kind of proxies, it must be one terrible mess. First order of businesses would be to fix the code at the very least.
The Spring code is still fine. You didn't quote the entire advisory:
> If existing code is using Proxy.getProxyClass and the Constructor.newInstance method to create a proxy instance, it will fail with IllegalAccessException if the caller is not in the same runtime package as the non-public proxy interface. For such code, it requires a source change to either (1) call Constructor.setAccessible to set the accessible flag to true, or (2) use the Proxy.newProxyInstance convenience method.
To end up in that specific condition is fairly difficult and usually means something is wrong with the code to begin with. It's still a very easy fix in any event (adding in 1 extra line of code before the call).
> I would put lambdas in the "major shifts in the language" category.
Recompile away, stuff just works. Add lambdas to your code, compile. Still works. This isn't like 1.2 where you were adding collections classes (arguably for the first time) or 1.5 where you encounter generics.
To be fair, it probably wouldn't be too hard to write a parser/translator to turn into into a more readable language. Unlike something like Perl of C++, where you'd pretty much have to be superhuman to write a parser single-handedly.
But I really believe the future of software is affected more by having better programmers rather than having better languages.
On average, I believe the quality of programmers will decline, simply because as they demand rises more and more people will come to the field that don't do it out of interest/passion but because it a profitable profession. Not that this is already the case today - I think it's a trend that's already begun and will probably continue this way.
This was already happening during the first dot.com boom. The time I studied CS. In Belgium banks would provide cars and a paycheck while you were still graduating in your last year.
This attracted a lot of people who weren't really passionated about programming.
Now years later I was hiring during the bank crisis and I interviewed CS students who got their degree but couldn't find a job. I couldn't understand that if you have your degree and are out of job in 2 years you haven't written a single line of code on a hobby project. But these people exist.
> But I really believe the future of software is affected more by having better programmers rather than having better languages.
Better programmers will likely make better languages. Undoubtedly a good programmer can learn to program in any language, because its the same process, but languages do certainly have their limitations.
Java input output api is cumbersome, so is its date api. That is why you use Apache commons and yoda time to deal with them.
He sounds like someone who never learn Java in the first place. Neither he learned what it is good for, what it is bad for. I think that if you interview in some language, you should understand what kind of problems are easy to solve in that language and which are hard or never done.
If I have to write libraries less input output example in interview, my code will be ugly and long. I'm not saying that interview should not ask these questions, it tests whether the candidates ability to find his way around api he uses rarely. It is needed skill, so no problem there.
If I have to design complicated system, adjust it to changing requirements and maintain it for years, I feel most comfortable in Java. Type safety, tools and language itself allow me to focus on the system itself and how systems parts cooperate with each other.
He also sounds like somebody who is biased against whoever uses java, because he worked once in bad java shop. It sounds that it really does not matter what those people would do, they used java, so they are incapable in his eyes.
"In Java, you can forget about doing it in the cleanest or the best way, because that is impossible. Whatever you do, however hard you try, the code will come out mediocre, verbose, redundant, and bloated."
I think the author takes it a bit too far: It's possible that the Java programmers have valuable skills that we could use, despite their inability to produce even a trivial working program in a short amount of time.
The fact that I/O management is cumbersome in Java doesn't relate to the ability of Java programmers to provide value.
Yes, but it requires knowing library functions that many Java programmers wouldn't have used for years and would need to look up; you just don't interact with console in Java-world not nearly as much as, say, in Perl-world.
Doing it through, say, docs.oracle.com to check what's the stdin interface - that is quite easy, but writing it on a whiteboard from scratch would fail many Java developers.
> Yes, but it requires knowing library functions that many Java programmers wouldn't have used for years and would need to look up; you just don't interact with console in Java-world not nearly as much as, say, in Perl-world.
People keep thinking that there are special functions involved in this solution for interacting with the console (which by itself is telling). Let's pretend it was just copying from an InputStream to a PrintStream. Those are both interfaces that most Java developers should be quite familiar with.
I dunnoh... reading data, writing data. Even if you only ever talk to a database JDBC has API's for accessing data through a stream. It's kind of the default way to handle networking and file data...
Sure, but what am I going to do with that data? It's very rare that I'd want to twiddle the individual bits; 99% of the time a stream is an opaque handle that I pass through to an ObjectInputStream or an XML parser or write to an http response.
Where would your code see an InputStream? "Interacting with console" is overly specific, yes. However - the other two usecases are handling files and network sockets, and in the java world, you generally don't touch streams of bytes or lines even in those cases.
The unix approach of treating most things as streams of bytes or lines tends to be abstracted - if I'm writing socket-based communications, then an InputStream exists there; but if I'm making web requests, then it's through a library where no streams are exposed. If I'm writing a logging library, then a PrintStream exists there; but if I'm doing proper logging, then again, it uses a library that doesn't expose any streams to a public interface, just the appropriate methods. Custom file formats would involve handling streams directly, but general practice in line-of-business apps nowadays is to never do that - you just [de]serialize to json/xml/something else standartized; and again that's done by a library that uses streams but doesn't expose them.
These things are trivial to do in java, but what I'm saying is that java is very often used in large codebases that don't touch raw streams at all. Students in java lessons use InputStream&PrintStream, but after starting work, promptly forget what the methods are called as they're used rarely.
> However - the other two usecases are handling files and network sockets, and in the java world, you generally don't touch streams of bytes or lines even in those cases.
I think you live in a pretty rarified Java world.
> The unix approach of treating most things as streams of bytes or lines tends to be abstracted - if I'm writing socket-based communications, then an InputStream exists there; but if I'm making web requests, then it's through a library where no streams are exposed.
Except if you want to handle large amounts of data efficiently, you end up using streams to read and or write those web requests.
> Custom file formats would involve handling streams directly, but general practice in line-of-business apps nowadays is to never do that - you just [de]serialize to json/xml/something else standartized; and again that's done by a library that uses streams but doesn't expose them.
...and I guess you never have to debug anything or understand what is happening underneath?
> Students in java lessons use InputStream&PrintStream, but after starting work, promptly forget what the methods are called as they're used rarely.
Then why do you think they teach 'em? Aren't all subsequent concepts built on top of them?
> Except if you want to handle large amounts of data efficiently, you end up using streams to read and or write those web requests.
No you wouldn't, unless you're working on some tiny project where using raw servlets might be justified (though I'd be highly suspicious of anyone doing raw servlets). Most any other framework will provide higher level abstractions such as Play's Iteratees or variations of sendfile to handle the streaming for you. You're job is usually just to configure the proper marshaling setup so that your higher level object(s) delivered by your controller methods are properly serialized by the lower levels of the framework.
Occasionally you may need to actually write marshalling code but you should definitely be wary that you're doing it wrong if so.
I have a healthy love/hate relationship with Java - but that's the first thing I thought of too. Alternatively you could read into a byte[] buf and not have any casting.
This is valid JDK 1 code. You only need to read the Javadoc for InputStream and PrintWriter. I think the author needs to check his biases.
> I have a healthy love/hate relationship with Java - but that's the first thing I thought of too. Alternatively you could read into a byte[] buf and not have any casting.
Okay, that kind of points to the problem. You don't see anything wrong with that code beyond the casting (and avoiding casting is the wrong reason to read in to a byte[].. which opens up some additional complexity too).
Sigh so half of an interview is to probe the candidate's knowledge and the other half is to understand their thought process.
So my ideal impl in java would be:
public class F {
public static void main(String [] args) throws Exception {
byte[] buf = new byte[256];
int len = -1;
while ( (len = System.in.read(buf)) != -1) {
System.out.write(buf, 0, len);
}
System.out.flush();
}
}
In python
#!/usr/bin/env python -u
import sys
while True:
buf = sys.stdin.read(256)
if buf:
sys.stdout.write(buf)
else:
break
Which both feel roughly the same. Although I kind of wish python would let me assign within the expression - just in this case. The similarity boils down to the fact that they're sitting on top of posix read and write calls. There's not much variation you can get from that.
The differences get down to fd stream flushing. Python we enable unbuffered io with -u, java we must flush. In C++ we can count on all FDs being flushed in atexit.
You certainly can muck this problem up for binary files and different charsets if you're not careful. But the OP's solution still works in many cases. A fine first answer. Any time a candidate writes code for you during an interview, the first answer will most likely have issues (stress, trying to finish quickly to impress, etc). I care very little about that stuff if there answer is roughly functional. After they have their first stab out, then you go thru the 'why did you do it this way?' 'what corner cases might you be concerned about?' and so on. The answers to those questions will let you make a good estimate of their knowledge and competence.
So, my first follow up would be: why are you bothering to read in to a byte array, and why a 256 byte array?
And to be clear... the correct answer is that in Java it basically buys you nothing but some extra overhead initializing an array and in Python it merely saves you trips through the repl loop. Either way the choice of 256 bytes is arbitrary.
I'd phrase it in a nicer way in an interview, but on a forum: You're wrong. The explicit buffering afforded by read(byte[]) & write(byte[], off, len) vs. read() & write(int) saves demonstrable time as file size increases. 256 - yeah arbitrary :) tweak as necessary.
on my junky MBP running java 6 -
read(byte[]) & write(byte[], int, int):
real 0m6.588s
user 0m0.876s
sys 0m1.406s
vs. read() & write(int)
real 0m16.836s
user 0m10.624s
sys 0m4.245s
vs the mighty cat - < in > out:
real 0m4.609s
user 0m0.015s
sys 0m0.458s
For a 150 mb file.
I'd say read(byte[]) / write(byte[], int, int) performed pretty well.
Now some points.
System.in is an InputStream, System.out is a PrintStream. Assuming anything more about their buffering nature is wrong. AFIAK there is nothing in the java spec that spells out any other explicit behaviour. So if you want to ensure your code works properly, code against the interfaces you're given, not the implementations you expect are sitting behind them.
This question (and stdin/stdout/stderr questions in general) are heavily biased in favour of devs comfortable of working in a Unix-y environment. If you're fine with short changing people that use that other OS that's cool. But if you want a 'trivial' demonstration of programming skill - a FizzBuzz type of question is much less biased way of achieving that.
Okay, I stand corrected that you can achieve some win due to doing buffering yourself. I guess it does depend on your implementation (though I'd think the JIT would eventually get around to eliminating most of that overhead you see), though you should still have buffering as per the platform's standard runtime, which I'd expect in most cases would be not insignificant.
> So if you want to ensure your code works properly, code against the interfaces you're given, not the implementations you expect are sitting behind them.
A test which the original code, and your initial review, failed on multiple fronts (failed to handle character encoding issues and failed to flush the output stream before exiting).
> This question (and stdin/stdout/stderr questions in general) are heavily biased in favour of devs comfortable of working in a Unix-y environment.
I honestly find it hard to believe that Java devs would have their skills sets be terribly different regardless of platform they run on, and I really would think people would learn the basics of working with streams regardless of the platform they work with, but I grok the gist of what you are saying.
> But if you want a 'trivial' demonstration of programming skill - a FizzBuzz type of question is much less biased way of achieving that.
FizzBuzz doesn't really test for knowledge of the language's libraries though. I always thought the purpose of these tests was more to validate that the programmer had successfully coded in the past, rather than any demonstration of skill.
>(though I'd think the JIT would eventually get around to eliminating most of that overhead you see)
150000000 iterations of a loop would warm the coldest JIT. JIT speeds up bytecode execution - but if you trace the execution of this code you'll see we often end up crossing between JVM land and native land via JNI to push output to write(2) or pull input from read(2). Crossing the JNI boundary is not free and cannot be optimized with JIT (there's lots of data copying back and forth - maybe some memory pinning etc). Using explicit buffers, you pay this overhead less often. Increasing the buffer size reduces the overhead - but of course with diminishing returns. Using read()/write(int) you pay this penalty more frequently. In general it's almost always a bad idea to use single element methods when the interface also exposes bulk methods and you want to do bulk work.
> A test which the original code, and your initial review, failed on multiple fronts (failed to handle character encoding issues and failed to flush the output stream before exiting).
Mea culpa - OP & I had similar idea and a quick scan of the code seemed generally correct. If I was interviewing him / her I would spend more than a second reading the provided code.
> I honestly find it hard to believe that Java devs would have their skills sets be terribly different regardless of platform they run on, and I really would think people would learn the basics of working with streams regardless of the platform they work with, but I grok the gist of what you are saying.
I'd still argue that stdin/stdout/stderr are instances of IO streams. I'd hope all programmers are relatively confident with manipulating IO streams. But these particular instances are really familiar to people working in Unix and uncommon to Windows people. I'd rather have the candidate thinking about streams and not fumbling in the back of their mind kind of remembering what stdout is.
> FizzBuzz doesn't really test for knowledge of the language's libraries though.
Granted - but I think this thread illustrates that there are a ton of other aspects besides standard library knowledge in play when you dig into this question. If you want to know if the person sitting in front of you can program, FizzBuzz. If you want to know if they grasp the language's standard libraries - ask them a question that requires using collections. If you want to see if they understand the platform their running on do something with File IO.... and so on.
> I'd still argue that stdin/stdout/stderr are instances of IO streams. I'd hope all programmers are relatively confident with manipulating IO streams. But these particular instances are really familiar to people working in Unix and uncommon to Windows people.
So, if I reframed the question as "copy the contents of one file to another" and asked them to write a class that implements:
public void copy(java.io.InputStream in, java.io.PrintStream out);
Slightly off topic: but I just wanted to thank you for continuing the thread in this fashion. I found it educational (in a 'how to teach/how to interview' way)
You know, I kind of thought he was joking that Java programmers messed this stuff up.
I was so wrong.
Three things wrong. The first is pedantic: you need to import IOException. The second though is one of those "scream out loud at the universe* questions: why the heck are you calling print() instead of write()?
Finally, do you think maybe you might need to worry about buffering of System.out's stream?
I'm not sure why you'd want to use a catch, but I agree there is more than one way to solve the problem. I was merely pointing out one thing that would prevent the code from passing the test framework.
Sorry, I didn't think I was telling you something which you didn't already know. I just saw a hole in the pedantry and felt a strange need to point it out. Now that I've typed that, I realize what a horrible person I am.
As to why you'd want to use a catch, I think it's kind of sloppy to let the user see an uncaught exception. You might as well just do
public static void main(String args[]){
try {
...
} catch (Exception e) {
System.out.println("This is horrible software, and you shouldn't use it.");
}
}
... as that's what many users already see when exception goes uncaught.
I could see a try/catch with a System.exit(-1) maybe, but arguably the default handler does the right thing (returns an error code and writes diagnostics to stderr).
> He wrote the code to show you that you don't need to import IOException you can use a catch all to avoid a throws statement in the method header.
You're conflating two things. I could just as easily have caught Throwable or Exception and not needed the import. The question is: what would you actually put in the handler that would be so much better? The actually provided sample code is much worse, as it prints to System.out instead of System.err, and it doesn't report an error to the parent process, so you muddy up the output (imagine if the file you were copying actually ended in "This is horrible software, and you shouldn't use it.", how would you even know) and there is not a terribly easy way to detect an error happened.
> This is bad code as he said.
It's not bad code to declare a static exception as escaping your method, particularly if you don't have any logic for handling it. It's bad code to have an exception handler that doesn't.
It mostly is language specific though isn't it? Take python: IOError is a global, one main way to print, you don't have to worry about the output buffer.
Oh no. Python has lots of ways to print. You can actually pretty easily hose that part up in Python, and Python doesn't require the flush because it automatically closes/flushes the stream. In general (as in, if you didn't know you were using sys.in and sys.out) in Python you'd want to use a "with" statement to ensure that really happens.
So, for example, if you are in Python3, sys.in and sys.out are by default in text mode, which is not going to end well for anyone.
Well, if I were making the test framework for this test, I'd only send ASCII text to the programs.
It's a trivial test, so I'll give you trivial input and not have you worry about "what if someone gives me random bytes".
The test isn't to demonstrate you know off the top of your head how to deal with an edge case. But if it were and I were allowed to pick my language, I'd pick bash and just write
> The test isn't to demonstrate you know off the top of your head how to deal with an edge case.
The only edge case is knowing you need to flush the output, which is relevant whether you send ASCII text or not. The other edge cases around ASCII are just whether you use the correct API's or not.
> Finally, do you think maybe you might need to worry about buffering of System.out's stream?
print() won't flush to the console unless you pass '\n' and auto-flushing is on. It will flush its internal buffer, but that's okay! The default System.out uses a BufferedOutputStream anyway:
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
...
new PrintStream(new BufferedOutputStream(fdOut, 128), true)
So using print() instead of write() shouldn't cause any extra system calls, although there many be a small CPU cost.
So what are you saying is the problem then? That writing to the BufferedOutputStream for each character is CPU-inefficient and he should be doing this?
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[1 << 12];
for (;;) {
int nRead = System.in.read(buffer);
if (nRead == -1) return;
System.out.write(buffer, 0, nRead);
}
}
If so, fair enough, but it's reasonable to go with the simpler solution if you're not given any particular performance requirements.
No, I'm saying you are already using a BufferedInputStream and a BufferedOutputStream. That is the problem: you aren't guaranteeing your output matches your input.
Nothing beyond an automatic flush/close of stdout on exit. The python code above is also reading the entire file in to memory before writing it out to disk, which isn't exactly wise. Aside from the addition of a flush at the end, the correct Java code for this is simply a loop with an exit test over a read() & write() though, which is really no different from the proper Python code.
.read() will read the entire contents of the file object into memory. That's fine if you're just doing `io.py < smallfile.txt`, but if the file is huge you'll run out of memory. And stdin is an infinite stream (eg. `io.py < /dev/urandom`), your Python code will never print anything. If you write `for line in sys.stdin: sys.stdout.write(line)` instead, you'll solve these problems by buffering line-by-line.
There seems to be confusion on how to write this properly, so don't feel bad about missing this (or alternatively feel bad for all of humanity). I believe this Java code I posted elsewhere handles things just fine: https://gist.github.com/cbsmith/9755809
So, that actually is going to have problems with binary data in the file. However, you are correct it doesn't need to be terribly verbose (not as efficient as it could be, but that is easily fixable): https://gist.github.com/cbsmith/9755809
It's amazing though how often the solutions posted are just wrong.
I couldn't care less what language I am using. I care about the quality of the libraries. That's what helps you get shit done fast. And JVM has a shit-ton of high quality libraries.
I knew a guy named Steve who ensured job security using Delphi. He wrote this malevolent and semi-sentient framework called The Framework, that managed to combine the ugliness of COBOL with the programmer-friendliness of... well, COBOL, now I think of it. Delphi has a couple of different flavours of inheritence built in -- object inheritence, controls owning subcontrols, TFrames embedded in TForms -- but The Framework increased that number somewhat. From memory, I think I counted nine different kinds of hierarchy, all intermingling in weird and utterly undocumented ways.
For all I know, he's probably still working there. The poor, poor bastard.
Ah yes, very true. I am not in games or finance but I use it day to day. Doesn't seem to be the language of the month and a lot of hatred is directed towards it, which I cannot fathom entirely.
Never understood the hate towards Java on HN. Java is not perfect by any means but every one of the other languages he mentions in that article (Perl, Python, Ruby, JavaScript) also has their shortcomings. People focus way too much on technology and not enough on the results.
It reminds me of a great post by Coda Hale a couple of years back where he was explaining why he switched back to Java from Scala (which was hot shit on HN at the time):
"The world has yet to take me aside and ask me for my opinion of it, and in the past few years I’ve found that it’s far more profitable to build things rather than tilt at windmills."
I think part of the hate may come from people trying to code Java in a text editor rather than an IDE. Java's verbosity/class-heaviness really doesn't bother me at all when I'm in an IDE. OTOH, coding java in a text editor is pretty frustrating.
That's a fair point. Programming in Java was what made me move from Emacs to Netbeans. Well, at least for Java, HTML, Javascript etc.
It's an environment that needs an IDE because of the large number of libraries and the large number of features delegated to libraries rather than the core language (which is an architectural decision that I approve of, BTW)
I wouldn't put C# and Java together. The former is significantly better more often compared to Scala then Java nowadays. Java is still a great language though.
I never used to understand it either until I got more exposure to other languages. Now I can't understand how anyone would voluntarily pick Java over other languages.
The codahale post is old news referencing issues which have already been fixed.
I really respect Coda Hale for the work he has done on Dropwizard, and shares his views on Java vs. scala.
As for the java-hate - in my 10 years of java-programming it has always been there. They used to complain about it not being portable enough, not performant enough, GC-pauses, start-up times, and lately that it's to verbose and non-functional. But java has persisted, and only improved over the years. I'm happy I've been able to (mainly) program in the same language for so many years. It makes me realize just how long it takes to truly master a programming language (or perhaps programming in general). I guess that's why they say "..it takes 2 weeks to learn a programming language, and 10 years to master it". It's an art, and the language is your tool.
437 comments
[ 2.8 ms ] story [ 299 ms ] threadThere are a lot of nervous and shy people. Easing them into the process with an 'icebreaker' question gives them a chance to open up for the real questions.
(1) This is an interview question, he's not asking you to be a professional stdin->stdout copier
(2) this isn't a micro optimisation problem:
(3) A surprising number of programmers can't program. Basic warmup questions are a good thing and can save a lot of your time http://blog.codinghorror.com/why-cant-programmers-program/(4) Even if this isn't his attempt, there's genuine depth to even this problem. If you do the obvious
There's a surprising amount of work going on behind the scenes that you can dive into discuss how I/O works, when would you do this using blocking vs. non-blocking I/O, when should you do your own buffering or let the language/library do it for you. But it's short enough to get started to get to those points very quickly.(5) I wouldn't hire/not hire someone based on style alone, but you can get a pretty good feel for it from short programs that actually work. If the tasks or snippets on which you interview are too short to be complete programs, you miss a lot of organisation and "shape of the code" kind of stuff from their style.
(6) Interviews are tough as an interviewee. Professional programmers aren't professional job interviewers and often it can be hard to read their mind to see what they are looking for in a particular question. "It's open ended, take it where you like" usually doesn't mean what it says on the tin. As far as going from "here's a question" to "here's an answer" with little ambiguity this is one of the better FizzBuzz type questions I've seen.
This reminded me of the interview for my first job. I was basically between a rock and a hard place so part of what follows was clearly, in retrospect, a bad sign, but the choice between job and no job but $20k in debt to cover, I took the job.
The shop was a C shop, embedded systems. When I went in to interview I was virtually a shoo-in (just learned I'd misspelled this for years as shoe-in) for the job due to a college classmate already working there and recommending me. The code segment was straightforward. It presented several "implementations" in C of functions to swap the values in two variables. That is:
Now, that obviously won't work in C. One of the implementations was correct, 3 were wrong (like the above snippet). I was asked which were wrong, why they were wrong, which was correct. I answered them all (note: this was a week 2 or 3 programming assignment when I took a course using C as an undergrad, it really seemed obvious to me), and the interviewer was surprised. I was told, "You're the first person to get all these questions correct."Like I said, warning signs. Alarm bells should have been going off. If the interviewer tells you that, that means that your colleagues couldn't answer those questions. That only occurred to me about 4 weeks later once I'd finished all my reading and project familiarization and was getting into really working with my new peers.
#!/bin/sh
cat
Ultimately java is just a tool. The culture around it shapes the macro picture but still.
Well neither does C, C++ as well. Nor does Scala actually.
There are a lot of good things about Java, namely the JVM, interfaces, great libraries, reflection and code generation, etc, etc. For example libraries like jmock/etc.
http://www.cplusplus.com/reference/functional/hash/
Ultimately, where does the language end, and the standard library begin? Whats the real difference? Yeah, so C++ and Java don't have built in syntax for hash tables. That's it?
Want to show off to the web CRUD hipsters, you can go Groovy, Grails and Play framework.
Want to show off to the Enterprise architect astronauts, you can go Hibernate, Spring, ElasticSearch and JBoss.
Want to show off to the Big Data ivory tower academics, you can go Weka, Lucene, Hadoop and Scala.
Want to show off to the esoteric language hipsters, you can go Clojure, JRuby, Jython, JScheme and Rhino.
Sun Microsystems and applets on IE6 live on in my big heart warmed up by hot cup of cappuccino beans.
(reason for liking Java)
Well, here are some other reason for liking Java: https://medium.com/i-m-h-o/da3b2c180e9c
But I really believe the future of software is affected more by having better programmers rather than having better languages.
Yes, it helps to have cool languages like Julia, Nimrod, Rust, even Scala (which I think is the best statically typed JVM language out there). But I tend to think that a good developer will be good in any language, Haskell, C, Java or LOLCODE.
I think that a good developer "forced" to use Java will find tools that bring out the good parts of the language: Dropwizard, Play framework / Akka, even latest versions of Spring and Java EE are much more convention over configuration and lightweight than before. They will use Guava and Apache commons to streamline common Java verbosity and bloat. They'll use Java 8 which allows much more robust and concise syntax to common problems.
But I don't think that the language is the problem. I think that a great developer will be able to tackle any problem with the language itself easily, because the real problem is not how to implement X, but more what is X. Designing the software correctly is the main problem at hand, not how to move input to output. This is what stackoverflow is for.
One last point about this all "I hate/like Java" type of post
1) If you write Java for your day job and hate it, either try to introduce something else (Clojure / Scala / Java 8 / Kotlin) If you can't introduce any of these then either accept your fate or just quit and find another job. If you can't find another job, then perhaps you deserve to stay and write Java so stop whining, it's not that bad (and one day you'll get to use Java 8).
2) If you don't write java for your day job but as a freelancer - start getting other non-java gigs. Not so many non Java jobs? well, continue to write Java bashing blog posts until people will stop using it I guess...
3) If you don't write Java for your day job or as a freelancer, then just stop complaining about it. There are million of other things (not just programming languages) out there worth complaining about. They can use your writing talent for a better cause.
Only new Java projects would actually use the Java 8 features anytime soon. Existing Java codebases will stick to their Java 6 installation for a long while. It could be years before lambdas are used to any significant degree. Look at how long it took for many Java 1.4 shops to actually upgrade to Java 5, let alone encourage developers to use its features. Even today a lot of places still allow and even encourage use of collections classes without the generics specified.
As long as you aren't writing Java code on Android, in which case you're still stuck at Java 6 (with a very small subset of Java 7 features that were added 3 years after Java 7 came out).
Not the fault of the Java language, really, but it is incredibly annoying how unclear Google has been on the future of their dialect of Java post the Oracle lawsuit.
https://code.google.com/p/googleappengine/issues/detail?id=3...
The funny thing is that google's own GWT requires it now.
Of course, if this is any indication it'll be several years before its safe to use even JDK7 features considering Android's update trends, let alone JDK8 ...
The NDK has all the support I need, when coupled with something like Qt/SDL/openFramerworks and C++11 feels better than Google's Java fork.
One worth noting: If existing code is using Proxy.getProxyClass and the Constructor.newInstance method to create a proxy instance, it will fail with IllegalAccessException. RFE 4487672
> If existing code is using Proxy.getProxyClass and the Constructor.newInstance method to create a proxy instance, it will fail with IllegalAccessException if the caller is not in the same runtime package as the non-public proxy interface. For such code, it requires a source change to either (1) call Constructor.setAccessible to set the accessible flag to true, or (2) use the Proxy.newProxyInstance convenience method.
To end up in that specific condition is fairly difficult and usually means something is wrong with the code to begin with. It's still a very easy fix in any event (adding in 1 extra line of code before the call).
(yeah, shouldn't happen in the best of all possible worlds, but may still happen anyway)
Recompile away, stuff just works. Add lambdas to your code, compile. Still works. This isn't like 1.2 where you were adding collections classes (arguably for the first time) or 1.5 where you encounter generics.
Sorry, no. That's just too far. Imagine being handed a codebase of LOLCODE.
I hope to God no one ever was or will be handed a codebase of LOLCODE for a "real" commercial system.
But if anyone ever does, it will sure be fun to hear about it in a blog post.
On average, I believe the quality of programmers will decline, simply because as they demand rises more and more people will come to the field that don't do it out of interest/passion but because it a profitable profession. Not that this is already the case today - I think it's a trend that's already begun and will probably continue this way.
This attracted a lot of people who weren't really passionated about programming.
Now years later I was hiring during the bank crisis and I interviewed CS students who got their degree but couldn't find a job. I couldn't understand that if you have your degree and are out of job in 2 years you haven't written a single line of code on a hobby project. But these people exist.
These people will be always there in any field.
Better programmers will likely make better languages. Undoubtedly a good programmer can learn to program in any language, because its the same process, but languages do certainly have their limitations.
He sounds like someone who never learn Java in the first place. Neither he learned what it is good for, what it is bad for. I think that if you interview in some language, you should understand what kind of problems are easy to solve in that language and which are hard or never done.
If I have to write libraries less input output example in interview, my code will be ugly and long. I'm not saying that interview should not ask these questions, it tests whether the candidates ability to find his way around api he uses rarely. It is needed skill, so no problem there.
If I have to design complicated system, adjust it to changing requirements and maintain it for years, I feel most comfortable in Java. Type safety, tools and language itself allow me to focus on the system itself and how systems parts cooperate with each other.
He also sounds like somebody who is biased against whoever uses java, because he worked once in bad java shop. It sounds that it really does not matter what those people would do, they used java, so they are incapable in his eyes.
"In Java, you can forget about doing it in the cleanest or the best way, because that is impossible. Whatever you do, however hard you try, the code will come out mediocre, verbose, redundant, and bloated."
Guess I was right about learning Java.
The fact that I/O management is cumbersome in Java doesn't relate to the ability of Java programmers to provide value.
Doing it through, say, docs.oracle.com to check what's the stdin interface - that is quite easy, but writing it on a whiteboard from scratch would fail many Java developers.
People keep thinking that there are special functions involved in this solution for interacting with the console (which by itself is telling). Let's pretend it was just copying from an InputStream to a PrintStream. Those are both interfaces that most Java developers should be quite familiar with.
The unix approach of treating most things as streams of bytes or lines tends to be abstracted - if I'm writing socket-based communications, then an InputStream exists there; but if I'm making web requests, then it's through a library where no streams are exposed. If I'm writing a logging library, then a PrintStream exists there; but if I'm doing proper logging, then again, it uses a library that doesn't expose any streams to a public interface, just the appropriate methods. Custom file formats would involve handling streams directly, but general practice in line-of-business apps nowadays is to never do that - you just [de]serialize to json/xml/something else standartized; and again that's done by a library that uses streams but doesn't expose them.
These things are trivial to do in java, but what I'm saying is that java is very often used in large codebases that don't touch raw streams at all. Students in java lessons use InputStream&PrintStream, but after starting work, promptly forget what the methods are called as they're used rarely.
I think you live in a pretty rarified Java world.
> The unix approach of treating most things as streams of bytes or lines tends to be abstracted - if I'm writing socket-based communications, then an InputStream exists there; but if I'm making web requests, then it's through a library where no streams are exposed.
Except if you want to handle large amounts of data efficiently, you end up using streams to read and or write those web requests.
> Custom file formats would involve handling streams directly, but general practice in line-of-business apps nowadays is to never do that - you just [de]serialize to json/xml/something else standartized; and again that's done by a library that uses streams but doesn't expose them.
...and I guess you never have to debug anything or understand what is happening underneath?
> Students in java lessons use InputStream&PrintStream, but after starting work, promptly forget what the methods are called as they're used rarely.
Then why do you think they teach 'em? Aren't all subsequent concepts built on top of them?
No you wouldn't, unless you're working on some tiny project where using raw servlets might be justified (though I'd be highly suspicious of anyone doing raw servlets). Most any other framework will provide higher level abstractions such as Play's Iteratees or variations of sendfile to handle the streaming for you. You're job is usually just to configure the proper marshaling setup so that your higher level object(s) delivered by your controller methods are properly serialized by the lower levels of the framework.
Occasionally you may need to actually write marshalling code but you should definitely be wary that you're doing it wrong if so.
Ya think!?
This is valid JDK 1 code. You only need to read the Javadoc for InputStream and PrintWriter. I think the author needs to check his biases.
Now Javascript... (just kidding).
Okay, that kind of points to the problem. You don't see anything wrong with that code beyond the casting (and avoiding casting is the wrong reason to read in to a byte[].. which opens up some additional complexity too).
So my ideal impl in java would be:
In python Which both feel roughly the same. Although I kind of wish python would let me assign within the expression - just in this case. The similarity boils down to the fact that they're sitting on top of posix read and write calls. There's not much variation you can get from that.The differences get down to fd stream flushing. Python we enable unbuffered io with -u, java we must flush. In C++ we can count on all FDs being flushed in atexit.
You certainly can muck this problem up for binary files and different charsets if you're not careful. But the OP's solution still works in many cases. A fine first answer. Any time a candidate writes code for you during an interview, the first answer will most likely have issues (stress, trying to finish quickly to impress, etc). I care very little about that stuff if there answer is roughly functional. After they have their first stab out, then you go thru the 'why did you do it this way?' 'what corner cases might you be concerned about?' and so on. The answers to those questions will let you make a good estimate of their knowledge and competence.
And to be clear... the correct answer is that in Java it basically buys you nothing but some extra overhead initializing an array and in Python it merely saves you trips through the repl loop. Either way the choice of 256 bytes is arbitrary.
on my junky MBP running java 6 -
read(byte[]) & write(byte[], int, int):
vs. read() & write(int) vs the mighty cat - < in > out: For a 150 mb file.I'd say read(byte[]) / write(byte[], int, int) performed pretty well.
Now some points.
System.in is an InputStream, System.out is a PrintStream. Assuming anything more about their buffering nature is wrong. AFIAK there is nothing in the java spec that spells out any other explicit behaviour. So if you want to ensure your code works properly, code against the interfaces you're given, not the implementations you expect are sitting behind them.
This question (and stdin/stdout/stderr questions in general) are heavily biased in favour of devs comfortable of working in a Unix-y environment. If you're fine with short changing people that use that other OS that's cool. But if you want a 'trivial' demonstration of programming skill - a FizzBuzz type of question is much less biased way of achieving that.
> So if you want to ensure your code works properly, code against the interfaces you're given, not the implementations you expect are sitting behind them.
A test which the original code, and your initial review, failed on multiple fronts (failed to handle character encoding issues and failed to flush the output stream before exiting).
> This question (and stdin/stdout/stderr questions in general) are heavily biased in favour of devs comfortable of working in a Unix-y environment.
I honestly find it hard to believe that Java devs would have their skills sets be terribly different regardless of platform they run on, and I really would think people would learn the basics of working with streams regardless of the platform they work with, but I grok the gist of what you are saying.
> But if you want a 'trivial' demonstration of programming skill - a FizzBuzz type of question is much less biased way of achieving that.
FizzBuzz doesn't really test for knowledge of the language's libraries though. I always thought the purpose of these tests was more to validate that the programmer had successfully coded in the past, rather than any demonstration of skill.
150000000 iterations of a loop would warm the coldest JIT. JIT speeds up bytecode execution - but if you trace the execution of this code you'll see we often end up crossing between JVM land and native land via JNI to push output to write(2) or pull input from read(2). Crossing the JNI boundary is not free and cannot be optimized with JIT (there's lots of data copying back and forth - maybe some memory pinning etc). Using explicit buffers, you pay this overhead less often. Increasing the buffer size reduces the overhead - but of course with diminishing returns. Using read()/write(int) you pay this penalty more frequently. In general it's almost always a bad idea to use single element methods when the interface also exposes bulk methods and you want to do bulk work.
> A test which the original code, and your initial review, failed on multiple fronts (failed to handle character encoding issues and failed to flush the output stream before exiting).
Mea culpa - OP & I had similar idea and a quick scan of the code seemed generally correct. If I was interviewing him / her I would spend more than a second reading the provided code.
> I honestly find it hard to believe that Java devs would have their skills sets be terribly different regardless of platform they run on, and I really would think people would learn the basics of working with streams regardless of the platform they work with, but I grok the gist of what you are saying.
I'd still argue that stdin/stdout/stderr are instances of IO streams. I'd hope all programmers are relatively confident with manipulating IO streams. But these particular instances are really familiar to people working in Unix and uncommon to Windows people. I'd rather have the candidate thinking about streams and not fumbling in the back of their mind kind of remembering what stdout is.
> FizzBuzz doesn't really test for knowledge of the language's libraries though.
Granted - but I think this thread illustrates that there are a ton of other aspects besides standard library knowledge in play when you dig into this question. If you want to know if the person sitting in front of you can program, FizzBuzz. If you want to know if they grasp the language's standard libraries - ask them a question that requires using collections. If you want to see if they understand the platform their running on do something with File IO.... and so on.
So, if I reframed the question as "copy the contents of one file to another" and asked them to write a class that implements:
Would that change the solution?I was so wrong.
Three things wrong. The first is pedantic: you need to import IOException. The second though is one of those "scream out loud at the universe* questions: why the heck are you calling print() instead of write()?
Finally, do you think maybe you might need to worry about buffering of System.out's stream?
> you need to import IOException
;-)Edit: Or if you want to be just as pedantic, and not write an obnoxious catch-all
As to why you'd want to use a catch, I think it's kind of sloppy to let the user see an uncaught exception. You might as well just do
... as that's what many users already see when exception goes uncaught.This is bad code as he said.
You're conflating two things. I could just as easily have caught Throwable or Exception and not needed the import. The question is: what would you actually put in the handler that would be so much better? The actually provided sample code is much worse, as it prints to System.out instead of System.err, and it doesn't report an error to the parent process, so you muddy up the output (imagine if the file you were copying actually ended in "This is horrible software, and you shouldn't use it.", how would you even know) and there is not a terribly easy way to detect an error happened.
> This is bad code as he said.
It's not bad code to declare a static exception as escaping your method, particularly if you don't have any logic for handling it. It's bad code to have an exception handler that doesn't.
There are some, but they aren't the ones people usually think of when they say, "I'd always use X instead of Java".
So, for example, if you are in Python3, sys.in and sys.out are by default in text mode, which is not going to end well for anyone.
It's a trivial test, so I'll give you trivial input and not have you worry about "what if someone gives me random bytes".
The test isn't to demonstrate you know off the top of your head how to deal with an edge case. But if it were and I were allowed to pick my language, I'd pick bash and just write
The only edge case is knowing you need to flush the output, which is relevant whether you send ASCII text or not. The other edge cases around ASCII are just whether you use the correct API's or not.
print() won't flush to the console unless you pass '\n' and auto-flushing is on. It will flush its internal buffer, but that's okay! The default System.out uses a BufferedOutputStream anyway:
So using print() instead of write() shouldn't cause any extra system calls, although there many be a small CPU cost.Obvious, right? Don't you love java.io? :)
Yes, which is the _problem_, not the _solution_.
To clarify: the problem isn't that the code makes too many syscalls.
Try doing this:
In python, this seems to work: import sys sys.stdout.write(sys.stdin.read())
What is being abstracted away/handled by python that I'm not seeing?
Except no. Then you run in to problems with a binary file that might not have a line break.
while (<>){ print };
What's so verbose about it?
It's amazing though how often the solutions posted are just wrong.
Use Clojure when you're paid by the project.
Use Haskell when you need to ensure job security.
For all I know, he's probably still working there. The poor, poor bastard.
I'd say, Use Java when you need to ensure job security. And it is.
It reminds me of a great post by Coda Hale a couple of years back where he was explaining why he switched back to Java from Scala (which was hot shit on HN at the time):
http://codahale.com/the-rest-of-the-story/
"The world has yet to take me aside and ask me for my opinion of it, and in the past few years I’ve found that it’s far more profitable to build things rather than tilt at windmills."
It's an environment that needs an IDE because of the large number of libraries and the large number of features delegated to libraries rather than the core language (which is an architectural decision that I approve of, BTW)
... it's not on HN. It's among the users to languages that aren't Java or C#.
The codahale post is old news referencing issues which have already been fixed.
As for the java-hate - in my 10 years of java-programming it has always been there. They used to complain about it not being portable enough, not performant enough, GC-pauses, start-up times, and lately that it's to verbose and non-functional. But java has persisted, and only improved over the years. I'm happy I've been able to (mainly) program in the same language for so many years. It makes me realize just how long it takes to truly master a programming language (or perhaps programming in general). I guess that's why they say "..it takes 2 weeks to learn a programming language, and 10 years to master it". It's an art, and the language is your tool.
I was complaining that Java was verbose in 1999.