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

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

Published in the Random EN group
Hello! Knowledge is power. The more knowledge you have for your first interview, the more confident you will feel at it. Analysis of questions and answers from interviews for a Java developer.  Part 12 - 1With a good amount of knowledge, you will be hard 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 analyzing 250+ questions for a Java developer . Analysis of questions and answers from interviews for a Java developer.  Part 12 - 2

103. What are the rules for checking inheritance exceptions?

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 those in a superclass/interface method.
That is, if we have an Animal interface with a method that throws an IOException :
public  interface Animal {
   void voice() throws IOException;
}
In the implementation of this interface, we cannot throw a more general throwable exception (e.g. Exception , Throwable ), but we can replace it with a derived 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 by the superclass constructor being thrown when the object is created.
Suppose the Animal class constructor throws a lot of exceptions:
public class Animal {
  public Animal() throws ArithmeticException, NullPointerException, IOException {
  }
Then the inheritor of the class in the constructor must also specify them:
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 the three exceptions considered:
public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. Could you code when the finally block fails?

First, let's remember what finally is . Previously, we considered the mechanism for catching exceptions: the try block outlines the catch area, while the catch block (blocks) is the code that will work when a certain exception occurs. Finally is the third block of code after finally , which 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 operation.(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 where finally won't work:
  • Crash of the program caused by critical system problems, or the fall of some Error that will “drop” the application (an example of an error is the same StackOwerflowError that occurs when the stack memory overflows).
  • When the deamon thread passes through the ry...finally block , the program terminates in parallel. 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 banal infinite loop, in try or catch , once in which the thread will remain there forever:

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

This question is very popular in newbie interviews, so there are a couple of these exceptional situations worth remembering. Analysis of questions and answers from interviews for a 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 means multiple catches for a single 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 is thrown in the try block, then the catch blocks alternately try to catch it from top to bottom, if some catch block succeeds, it gets the right to handle the exception, while the other blocks below can no longer try to catch it and handle it in their own way. Therefore, narrower exceptions are placed higher in the catch block chain, and wider exceptions are placed lower. For example, if we catch an exception of the Exception class in the first catch block , then the checked exceptions will not be able to get into the remaining blocks (the rest of the blocks with Exception heirs 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 the exception through catch , we are trying to find out its specific type through the instanceof method , which is used to check if the object belongs to a certain type, so that later we can narrow it down to that type without negative consequences. Both considered approaches can be applied in the same situation, but I said about the incorrectness of the question due to the fact that I would not call the second option good and have never met in my practice, at the same time, the first method with multicatches has become widespread spreading. Analysis of questions and answers from interviews for a 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, however, I will repeat this keyword - throw . Usage example (forcing an exception to be thrown):
throw new NullPointerException();

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

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 the program execution, but other than that, it can be called from any other code. That is, it is also subject to the usual rules for specifying checked exceptions that are thrown after throws :
public static void main(String[] args) throws IOException {
Accordingly, exceptions can also fall in it. If main was not called in some method, but was launched as a program start 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 a Java developer.  Part 12 - 5

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

Basic/basic means 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 for 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 initial value.
Read more about volatile here .
  • Runnable is an interface, by implementing which (in particular, its run method) in some 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 on a separate thread.
  • Thread is a class from which to inherit (while overriding the run method ):
public class CustomThread extends Thread {
   @Override
   public void run() {
       // некоторая логика
   }
}
And by creating an object of this class and running it using the start() method , we will start a new thread:
new CustomThread().start();
  • Concurrency is a package with tools for working in a multi-threaded environment.
It consists of:
  • Concurrent Collections is 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 are thread synchronization mechanisms (more flexible than the standard ones - synchronized, wait, notify, notifyAll).
  • Atomics are classes optimized for multi-threaded execution, it is for them that each operation is atomic.
Read more about the concurrent package here .

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

As far as I understand the question, synchronization between threads is about the key modifier - synhronized . This modifier can be placed either directly on the block:
synchronized (Main.class) {
   // некоторая логика
}
Or directly in the method signature:
public synchronized void move() {
   // некоторая логика}
As I said earlier, synhronized is a mechanism that allows you to close a block / method from other threads when one thread has already entered it. Imagine a block/method as a room. A certain stream, having come to it, will enter it and close it with a key, other streams, having come to the room and seeing that it is closed, will wait near it until it is released. Having done its work, the first thread leaves the room and releases the key. And it was not in vain that I constantly spoke 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 the synhronized block, we need to specify in parentheses the object on whose mutex we want to close the door:
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 synhronized on a method, we don't specify the object we want to close on, 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 synhronized here . wait()- a method that releases the mutex and puts the current thread into standby mode, as if attaching 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 release 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 a waiting 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 a waiting 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, it will not unfreeze anyone else).

  • NotifyAll() - 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 it ahead of schedule, before the completion of this method. And then what to do? Is it possible to use the stop() method on the Thread object ? No matter how! This method is considered obsolete and may cause system crashes. Well, 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 the stream, which should display a certain phrase on the screen until it stops completely: Analysis of questions and answers from interviews for a Java developer.  Part 12 - 6
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 terminates. 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, in the console we will see something like this:
Starting program execution A thread is executing some logic... A thread is executing some logic... A thread is executing some logic... A thread is executing some logic... A thread is executing some logic... A thread is executing some logic... End of program execution The thread is stopped !
And this means that our thread worked, displayed a certain number of messages to the console, and was successfully stopped. I note that the number of displayed messages from run to run will be different, sometimes the additional thread did not even display anything. As I noticed, it depends on the sleep time of the main thread, the longer it is, the less chance that the additional thread will not display anything. With a sleep time of 1ms, messages are almost never displayed, but if you set it to 20ms, it almost always works. Perhaps, with a short time, the thread simply does not have time to start and start its work, and it 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 (by default, this flag is false ) and its other interrupt() method - which sets this flag to true (when this flag is true , the thread should stop its work). Let's see 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 the execution will be the same as in the first case, but I like this approach more: we write less code and use more ready-made, standard functionality. Analysis of questions and answers from interviews for a Java developer.  Part 12 - 7This is where we will stop today.Analysis of questions and answers from interviews for a Java developer.  Part 12 - 8 Analysis of questions and answers from interviews for a Java developer.  Part 12 - 9
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION