在面试中提交了这份工作后,我没有得到这份工作,但是我没有反馈知道该代码块中包含哪些“不良”内容。

要求是:



通过已知端口和IP连接到服务器
以您选择的格式异步向服务器发送消息
计算并显示往返时间对于每个消息以及所有已发送消息的平均往返时间




解决方案应该不是那么困难。但是我只是不知道怎么了?设计不好?命名不好?错误的做法?

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

public class EchoClient {

    private String hostname;
    private int port;
    private Socket clientSocket;
    private BufferedReader inFromUser, inFromServer;
    private DataOutputStream outToServer;
    private double averageTime = 0;
    private int count = 0;

    public EchoClient(String hostname, int port){
        this.hostname = hostname;
        this.port = port;
        try {
            this.clientSocket = new Socket(this.hostname, this.port);
        } catch (UnknownHostException e) {
            System.out.println("Connection Error: unknown host");
            System.exit(1);
        } catch (IOException e) {
            System.out.println("Connection Error: connection refused");
            System.exit(1);
        }
        try{
            this.inFromUser = new BufferedReader( new InputStreamReader(System.in));
            this.outToServer = new DataOutputStream(this.clientSocket.getOutputStream());
            this.inFromServer = new BufferedReader(
                    new InputStreamReader(this.clientSocket.getInputStream()));
        } catch (IOException e) {
            System.out.println("Error on Initializing echoclient");
            System.exit(1);
        }

    }

    public void start(){
        System.out.println("Connecting to " + hostname + " with port No " + port);
        String msgSend;
        try {
            while ((msgSend = inFromUser.readLine()) != null){
                // sendMessage asynchronous
                sendMessage(msgSend, new Callback(){
                    // callback function and calculate the average time
                    public void callback(long timeUsed, String msgReceived){
                        averageTime = (count * averageTime + (timeUsed)) / (count + 1);
                        ++count;
                        System.out.println(msgReceived + 
                            " rtt=" +  (double)Math.round(timeUsed * 100)/100    + " ms" +
                            " artt=" + (double)Math.round(averageTime * 100)/100 + " ms");

                    }
                });    
            }
        } catch (IOException e) {
            System.out.println("Error on reading message from user");
        }
    }

    private void sendMessage(String message, Callback cb){
        Thread sendMessageThread = new Thread(new SendMessageRequest(message, cb));
        sendMessageThread.start();
    }

    interface Callback {
        public void callback(long time, String msg);
    }

    class SendMessageRequest implements Runnable{

        private String message;
        private Callback cb;
        SendMessageRequest(String message, Callback cb){
            this.message = message;
            this.cb = cb;
        }
        @Override
        public void run() {
            String msgReceived;
            long timeStart, timeEnd, timeUsed;
            try {
                timeStart = System.nanoTime();
                outToServer.writeBytes(this.message + '\n');
                msgReceived = inFromServer.readLine();
                timeEnd = System.nanoTime();
                // Calculate the time and get the output
                timeUsed = (timeEnd - timeStart) / 1000000;
                cb.callback(timeUsed, msgReceived);
            } catch (IOException e) {
                System.out.println("Error on sending message to server");
            }

        }

    }

    public static void showUsage(){
        System.out.println("Usage: java EchoClient [hostname] [portNo]");
    }
    /**
     * Entry of the program
     */
            public static void main(String[] args) {
        String hostname = "";
        int port = 0;
        if (args.length < 2){
            showUsage();
            System.exit(0);
        }
        else{
            hostname = args[0];
            port = Integer.parseInt(args[1]);
        }

        EchoClient client = new EchoClient(hostname, port);
        client.start();
    }
}


评论

任何不提供有关候选人任务的反馈的公司都是不值得工作的公司。

@旋转医生我不同意。首先,公司永远不会将简历发送回去,所以为什么要进行代码审查呢?这将要求审阅者花时间为可能是多个候选者的评论加注,最终他的决定可能归结为偏爱某人的代码风格而不是另一人的代码风格。在纸上发表这样的声明充其量是对抗性的。

@kojiro简历不是应征作品,不属于同一类别。我认为,如果我要求应聘者做任何工作(并创建一个经过单元测试打磨的优质源程序包),则我作为面试官应该准备与该人联系并让他知道结果,即使只是高级注释。如果样本太多,那么这样做所需的时间会比您没有入选的时间还长。另外,代码审查不必是对抗性的(我打电话给拒绝的大多数人都乐于得到反馈),但可以是建设性的。

#1 楼

我认为最大的问题是缺乏同步。您可以在同时运行的回调中修改averageTimecount变量。您应该同步此变量的访问。关于此主题的一本好书是:阅读《实践中的Java并发》,如果您有时间阅读的话,它非常有用。

其他一些事情: >我不喜欢内部类。参考:Effective Java Second Edition,第22项:优先使用静态成员类。
我还要创建一个EchoClientMain类,其中包含main方法并解析命令行参数。此外,我将移至新文件Callback匿名内部类,并创建一个Statistics类,该类负责计算和维护统计信息。 (请查看Wikipedia上的“单一责任原则”。)您应该抛出异常而不是System.exit()。该类不可重用,因为一个简单的错误会停止整个应用程序。只需创建一个自定义的异常类并抛出它即可:

try {
    this.clientSocket = new Socket(this.hostname, this.port);
} catch (final UnknownHostException uhe) {
    throw new EchoClientException("Connection Error: unknown host", uhe);
}


让调用者处理它们。在这种情况下,main方法应捕获EchoClientException并将其消息打印到控制台。

try {
    EchoClient client = new EchoClient(hostname, port);
    client.start();
} catch (final EchoClientException ece) {
    System.err.println(ece.getMessage());
}


您不应在构造函数中连接到服务器。我可以通过start()方法来实现。
关闭资源。创建一个stop()方法,以关闭打开的流。
至少检查null输入参数:有效的Java,项目38:检查参数的有效性

Robert C的清洁代码也是值得的阅读。

#2 楼

我想知道当他们要求您异步发送消息时,他们是否不希望您启动第二个线程。您的第二个线程同步进行处理。是的,它是在另一个线程上关闭的,但这可能是异步也可能不是异步。类似于库的功能:https://github.com/sonatype/async-http-client。

正如palacsint指出的那样,您尚未同步变量。我使我看起来好像您不知道自己在做什么。

我不喜欢的另一件事是您处理错误的方式。如果发生错误,我将关闭该应用程序,而不是将其写入标准错误并尝试继续进行。我还想显示有关该错误的更多信息,而不是该错误发生的简单事实。