News for hackers. Stuff that matters.
Re:Why I like Java by guelo on Tuesday March 25, 2014 @01:22AM (#7463991)
Is this what he's looking for?

  public static void main(String[] args) throws IOException {
      int ch;
      while ((ch = System.in.read()) != -1)
          System.out.print((char) ch);
  }
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @01:34AM (#7464048)
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?

Re:Why I like Java by dlubarov on Tuesday March 25, 2014 @02:21AM (#7464203)
> 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.

Obvious, right? Don't you love java.io? :)

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:25AM (#7464214)
> The default System.out uses a BufferedOutputStream anyway

Yes, which is the _problem_, not the _solution_.

To clarify: the problem isn't that the code makes too many syscalls.

Re:Why I like Java by dlubarov on Tuesday March 25, 2014 @02:59AM (#7464323)
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.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @03:09AM (#7464348)
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.

Try doing this:

    dd if=/dev/random of=test_file bs=4000 count=100
    java YourClass < test_file > test_output
    diff test_file test_output
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @03:53AM (#7464466)
Here's the simpler, likely slower, but nonetheless actually correct solution: https://gist.github.com/cbsmith/9755809
Re:Why I like Java by dlubarov on Tuesday March 25, 2014 @11:40AM (#7466485)
Oh, gotcha. The code above with "byte[] buffer" also works since write(byte[], int, int) flushes.
Re:Why I like Java by benjamincburns on Tuesday March 25, 2014 @01:50AM (#7464102)
I mean, if you really want to be pedantic...

> you need to import IOException

    try {
        ...
    } catch(Exception ex){ ... }
;-)

Edit: Or if you want to be just as pedantic, and not write an obnoxious catch-all

    try { 
        ... 
    } catch (java.io.IOException ex) { ... }
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:06AM (#7464153)
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.
Re:Why I like Java by benjamincburns on Tuesday March 25, 2014 @02:57AM (#7464317)
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.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @03:00AM (#7464324)
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).
Re:Why I like Java by catinsocks on Tuesday March 25, 2014 @10:57AM (#7466220)
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.

This is bad code as he said.

Re:Why I like Java by cbsmith on Wednesday March 26, 2014 @12:20AM (#7471566)
> 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.

Re:Why I like Java by ygra on Tuesday March 25, 2014 @09:37AM (#7465714)
Isn't there a Steam.copyTo(Stream) method somewhere? Or was that .NET?
Re:Why I like Java by dlubarov on Tuesday March 25, 2014 @12:00PM (#7466612)
Yes, Apache Commons has IOUtils.copy and Guava has a similar ByteStreams.copy.
Re:Why I like Java by guelo on Tuesday March 25, 2014 @02:09AM (#7464164)
Looks like I don't get the job.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:14AM (#7464186)
Here's the thing though... Those mistakes you made aren't language specific. What languages don't expose you to making similar mistakes?

There are some, but they aren't the ones people usually think of when they say, "I'd always use X instead of Java".

Re:Why I like Java by Goopplesoft on Tuesday March 25, 2014 @02:45AM (#7464279)
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.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @03:03AM (#7464332)
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.

Re:Why I like Java by anon4 on Tuesday March 25, 2014 @04:31AM (#7464589)
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

  cat
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @04:36AM (#7464604)
> 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.

Re:Why I like Java by brilee on Tuesday March 25, 2014 @02:03AM (#7464138)
Question: I see all this discussion about buffering and encoding and such.

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?

Re:Why I like Java by sjy on Tuesday March 25, 2014 @02:27AM (#7464218)
.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.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:30AM (#7464231)
> If you write `for line in sys.stdin: sys.stdout.writte(line)` instead, you'll solve these problems by buffering line-by-line.

Except no. Then you run in to problems with a binary file that might not have a line break.

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:21AM (#7464202)
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.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:32AM (#7464234)
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
Re:Why I like Java by zoodle on Tuesday March 25, 2014 @03:10AM (#7464355)
Any language right? Here's classic C++.

  #include <iostream>

  int main ()
  {
    std::cout << std::cin.rdbuf();
    return 0;
  }
Re:Why I like Java by einhverfr on Tuesday March 25, 2014 @06:55AM (#7465010)
In perl:

while (<>){ print };

Re:Why I like Java by jweese on Tuesday March 25, 2014 @10:38AM (#7466095)

    perl -pe ""
Re:Why I like Java by thomaswk on Tuesday March 25, 2014 @01:34AM (#7464046)
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.

Now Javascript... (just kidding).

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @01:49AM (#7464098)
> 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).

Re:Why I like Java by thomaswk on Tuesday March 25, 2014 @02:44AM (#7464272)
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.

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @02:53AM (#7464299)
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.

Re:Why I like Java by thomaswk on Tuesday March 25, 2014 @03:30AM (#7464406)
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.

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @03:49AM (#7464456)
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.

Re:Why I like Java by thomaswk on Tuesday March 25, 2014 @05:37AM (#7464782)
>(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.

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @08:46AM (#7465456)
> 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);
Would that change the solution?
Re:Why I like Java by Goosey on Tuesday March 25, 2014 @10:47AM (#7466162)
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)
Re:Why I like Java by marvy on Tuesday March 25, 2014 @01:32AM (#7464037)
I think so. Or something like that. Might be better to use "write" instead of "print", to avoid character encoding issues.
Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @01:46AM (#7464091)
> Might be better to use "write" instead of "print", to avoid character encoding issues.

Ya think!?

Re:Why I like Java by chatman on Tuesday March 25, 2014 @03:20AM (#7464379)
public static void main(String[]args) throws IOException {

  Scanner sc = new Scanner(System.in);

  String line;

  while((line=sc.readLine())!=null)

     System.out.println(line);
}

What's so verbose about it?

Re:Why I like Java by cbsmith on Tuesday March 25, 2014 @10:43AM (#7466126)
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.

Re:Why I like Java by jsight on Tuesday March 25, 2014 @10:42AM (#7466118)
You didn't import Scanner, and java.util.Scanner (what I assume you are using) does not have a readLine method. :)