JavaRush /Java Blog /Random EN /Analysis of questions and answers from interviews for Jav...

Analysis of questions and answers from interviews for Java developer. Part 12

Published in the Random EN group
Hello! Knowledge is power. The more knowledge you have before your first interview, the more confident you will feel at it. Analysis of questions and answers from interviews for Java developer.  Part 12 - 1With a good amount of knowledge, you will be difficult to confuse, and at the same time you will be able to pleasantly surprise your interviewer. Therefore, today, without further ado, we will continue to strengthen your theoretical base by examining 250+ questions for a Java developer . Analysis of questions and answers from interviews for Java developer.  Part 12 - 2

103. What are the rules for checking exceptions in inheritance?

If I understand the question correctly, they are asking about the rules for working with exceptions during inheritance, and they are as follows:
  • An overridden or implemented method in a descendant/implementation cannot throw checked exceptions that are higher in the hierarchy than the exceptions in the superclass/interface method.
That is, if we have a certain Animal interface with a method that throws IOException :
public  interface Animal {
   void voice() throws IOException;
}
In the implementation of this interface, we cannot throw a more general thrown exception (for example, Exception , Throwable ), but we can replace it with a descendant exception, such as FileNotFoundException :
public class Cat implements Animal {
   @Override
   public void voice() throws FileNotFoundException {
// некоторая реализация
   }
}
  • The subclass constructor must include in its throws block all exception classes thrown by the superclass constructor that is called upon when creating the object.
Suppose the Animal class's constructor throws a lot of exceptions:
public class Animal {
  public Animal() throws ArithmeticException, NullPointerException, IOException {
  }
Then the class heir must also indicate them in the constructor:
public class Cat extends Animal {
   public Cat() throws ArithmeticException, NullPointerException, IOException {
       super();
   }
Or, as in the case of methods, you can specify not the same exceptions, but more general ones. In our case, it will be enough to specify a more general exception - Exception , since this is the common ancestor of all three exceptions considered:
public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. Could you write code for when the finally block will not be executed?

First, let's remember what finally is . Previously, we looked at the mechanism for catching exceptions: the try block outlines the catching area, while the catch block(s) is the code that will work when a specific exception is thrown. Finally is the third block of code after finally that is interchangeable with catch but not mutually exclusive. The essence of this block is that the code in it always works, regardless of the result of the try or catch (regardless of whether an exception was thrown or not). Cases of its failure are very rare and they are abnormal. The simplest case of failure is when the System.exit(0) method is called in the code above , which terminates the program (extinguishes it):
try {
   throw new IOException();
} catch (IOException e) {
   System.exit(0);
} finally {
   System.out.println("Данное сообщение не будет выведенно в консоль");
}
There are also some other situations in which finally will not work:
  • Abnormal termination of the program caused by critical system problems, or the fall of some Error that will “crash” the application (an example of an error can be the same StackOwerflowError that occurs when the stack memory overflows).
  • When the deamon thread passes through the ry...finally block and in parallel with this the program ends. After all, the deamon thread is a thread for background actions, that is, it is not a priority and mandatory, and the application will not wait for its work to finish.
  • The most commonplace infinite loop, in try or catch , once in which the flow will remain there forever:

    try {
       while (true) {
       }
    } finally {
       System.out.println("Данное сообщение не будет выведенно в консоль");
    }

This question is quite popular in interviews for newbies, so a couple of these exceptional situations are worth remembering. Analysis of questions and answers from interviews for Java developer.  Part 12 - 3

105. Write an example of handling multiple exceptions in one catch block

1) Perhaps the question was asked incorrectly. As far as I understand, this question refers to multiple catches for one try block :
try {
  throw new FileNotFoundException();
} catch (FileNotFoundException e) {
   System.out.print("Упс, у вас упало исключение - " + e);
} catch (IOException e) {
   System.out.print("Упс, у вас упало исключение - " + e);
} catch (Exception e) {
   System.out.print("Упс, у вас упало исключение - " + e);
}
If an exception occurs in a try block , then the catch blocks alternately try to catch it from top to bottom. If a certain catch block succeeds, it gets the right to handle the exception, while the rest of the blocks below will no longer be able to try to catch it and process it in their own way. Therefore, narrower exceptions are placed higher in the catch block chain, and broader exceptions are placed lower. For example, if in our first catch block an exception of the Exception class is caught , then checked exceptions will not be able to get into the remaining blocks (the remaining blocks with Exception descendants will be absolutely useless). 2) The question was asked correctly. In this case, our processing will look like the following:
try {
  throw new NullPointerException();
} catch (Exception e) {
   if (e instanceof FileNotFoundException) {
       // некоторая обработка с сужением типа (FileNotFoundException)e
   } else if (e instanceof ArithmeticException) {
       // некоторая обработка с сужением типа (ArithmeticException)e
   } else if(e instanceof NullPointerException) {
       // некоторая обработка с сужением типа (NullPointerException)e
   }
Having caught an exception through catch , we try to find out its specific type through the instanceof method , which is used to check whether an object belongs to a certain type, so that later we can narrow it down to this type without negative consequences. Both considered approaches can be used in the same situation, but I said that the question is incorrect because I would not call the second option good and have never seen it in my practice, while at the same time the first method with multicatches has received widespread attention. spreading. Analysis of questions and answers from interviews for Java developer.  Part 12 - 4

106. Which operator allows you to force an exception to be thrown? Write an example

I have already used it several times above, but nevertheless I will repeat this keyword - throw . Example usage (forcing an exception):
throw new NullPointerException();

107. Can the main method throw a throws exception? If so, where will it be transferred?

First of all, I want to note that main is nothing more than a regular method, and yes, it is called by the virtual machine to start executing the program, but besides this, it can be called from any other code. That is, it is also subject to the usual rules for specifying checked exceptions after throws :
public static void main(String[] args) throws IOException {
Accordingly, exceptions may also occur in it. If main was not called in some method, but was started as a program launch point, then the exception thrown by it will be handled by the .UncaughtExceptionHandler interceptor . This handler is one per thread (that is, one handler in each thread). If necessary, you can create your own handler and set it using the setDefaultUncaughtExceptionHandler method called on the Thread object .

Multithreading

Analysis of questions and answers from interviews for Java developer.  Part 12 - 5

108. What tools do you know for working with multithreading?

Basic/Basic Tools for Using Multithreading in Java:
  • Synchronized is a mechanism for closing (blocking) a method/block when a thread enters it, from other threads.
  • Volatile is a mechanism for ensuring consistent access to a variable by different threads, that is, with the presence of this modifier on a variable, all assignment and reading operations must be atomic. In other words, threads will not copy this variable to their local memory and change it, but will change its original value.
Read more about volatile here .
  • Runnable is an interface that can be implemented (in particular, its run method) in a certain class:
public class CustomRunnable implements Runnable {
   @Override
   public void run() {
       // некоторая логика
   }
}
And having created an object of this class, you can start a new thread by setting this object in the constructor of the new Thread object and calling its start() method :
Runnable runnable = new CustomRunnable();
new Thread(runnable).start();
The start method runs the implemented run() method in a separate thread.
  • Thread is a class, inheriting from which (while overriding the run method ):
public class CustomThread extends Thread {
   @Override
   public void run() {
       // некоторая логика
   }
}
And by creating an object of this class and launching it using the start() method , we will thereby launch a new thread:
new CustomThread().start();
  • Concurrency is a package with tools for working in a multi-threaded environment.
It consists of:
  • Concurrent Collections - a set of collections specialized for working in a multi-threaded environment.
  • Queues - specialized queues for a multi-threaded environment (blocking and non-blocking).
  • Synchronisers are specialized utilities for working in a multi-threaded environment.
  • Executors are mechanisms for creating thread pools.
  • Locks - thread synchronization mechanisms (more flexible than standard ones - synchronized, wait, notify, notifyAll).
  • Atomics are classes optimized for multi-threaded execution; each operation is atomic.
Read more about the concurrent package here .

109. Talk about synchronization between threads. What are the wait(), notify() - notifyAll() join() methods used for?

As far as I understand the question, synchronization between threads is about the key modifier - synchronized . This modifier can be placed either directly next to the block:
synchronized (Main.class) {
   // некоторая логика
}
Or directly in the method signature:
public synchronized void move() {
   // некоторая логика}
As I said earlier, synchronized is a mechanism that allows you to close a block/method from other threads when one thread has already entered it. Think of a block/method as a room. Some stream, having come to it, will enter it and lock it, other streams, having come to the room and seeing that it is closed, will wait near it until it is free. Having done its business, the first thread leaves the room and releases the key. And it was not for nothing that I constantly talked about the key, because it really exists. This is a special object that has a busy/free state. This object is attached to every Java object, so when using a synchronized block we need to indicate in parentheses the object whose mutex we want to close the door on:
Cat cat = new Cat();
synchronized (cat) {
   // некоторая логика
}
You can also use a class mutex, as I did in the first example ( Main.class ). When we use synchronized on a method, we don’t specify the object on which we want to close, right? In this case, for a non-static method, it will close on the mutex of the this object , that is, the current object of this class. The static one will close on the mutex of the current class ( this.getClass(); ). You can read more about mutex here . Well, read about synchronized here . Wait() is a method that releases the mutex and puts the current thread into standby mode, as if attached to the current monitor (something like an anchor). Because of this, this method can only be called from a synchronized block or method (otherwise, what should it free and what should it expect). Also note that this is a method of the Object class . More precisely, not one, but even three:
  • Wait() - puts the current thread into wait mode until another thread calls the notify() or notifyAll() method for this object (we'll talk about these methods later).

  • Wait (long timeout) - puts the current thread into wait mode until another thread calls the notify() or notifyAll() method on this object or the specified timeout expires .

  • Wait (long timeout, int nanos) - similar to the previous one, only nanos allows you to specify nanoseconds (more precise time setting).

  • Notify() is a method that allows you to wake up one random thread of the current synchronization block. Again, it can only be called in a synchronized block or method (after all, in other places it will not have anyone to unfreeze).

  • NotifyAll() is a method that wakes up all waiting threads on the current monitor (also used only in a synchronized block or method).

110. How to stop the flow?

The first thing to say is that when the run() method is fully executed , the thread is automatically destroyed. But sometimes you need to kill him ahead of schedule, before this method completes. So what should we do then? Perhaps the Thread object should have a stop() method ? No matter how it is! This method is considered outdated and may lead to system crashes. Analysis of questions and answers from interviews for Java developer.  Part 12 - 6Well, what then? There are two ways to do this: The first is to use your internal boolean flag. Let's look at an example. We have our own implementation of a thread that should display a certain phrase on the screen until it stops completely:
public class CustomThread extends Thread {
private boolean isActive;

   public CustomThread() {
       this.isActive = true;
   }

   @Override
   public void run() {
       {
           while (isActive) {
               System.out.println("Поток выполняет некую логику...");
           }
           System.out.println("Поток остановлен!");
       }
   }

   public void stopRunningThread() {
       isActive = false;
   }
}
When using the stopRunning() method , the internal flag becomes false and the run method stops running. Let's run it in main :
System.out.println("Начало выполнения программы");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// пока наш основной поток спит, вспомогательный  CustomThread работает и выводит в коноль своё сообщение
thread.stopRunningThread();
System.out.println("Конец выполнения программы");
As a result, we will see something like this in the console:
Start of program execution The thread is executing some logic... The thread is executing some logic... The thread is executing some logic... The thread is executing some logic... The thread is executing some logic... The thread is executing some logic... End of program execution The thread is stopped !
This means that our thread worked, output a certain number of messages to the console and was successfully stopped. I note that the number of messages output will vary from run to run; sometimes the additional thread did not even output anything. As I noticed, this depends on the sleep time of the main thread, the longer it is, the less chance that the additional thread will not output anything. With a sleep time of 1ms, messages are almost never output, but if you set it to 20ms, it almost always works. Perhaps, when the time is short, the thread simply does not have time to start and begin its work, and is immediately stopped. The second way is to use the interrupted() method on the Thread object, which returns the value of the internal interrupt flag (this flag is false by default ) and its other interrupt() method , which sets this flag to true (when this flag is true the thread should stop its work) . Let's look at an example:
public class CustomThread extends Thread {

   @Override
   public void run() {
       {
           while (!Thread.interrupted()) {
               System.out.println("Поток выполняет некую логику...");
           }
           System.out.println("Поток остановлен!");
       }
   }
}
Run in main :
System.out.println("Начало выполнения программы");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Конец выполнения программы");
The result of execution will be the same as in the first case, but I like this approach better: we write less code and use more ready-made, standard functionality. Analysis of questions and answers from interviews for Java developer.  Part 12 - 7That's where we'll stop today.Analysis of questions and answers from interviews for Java developer.  Part 12 - 8
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION