Sto svolgendo un esercizio sulle eccezioni e vorrei chiarirmi bene le idee.

Consideriamo queste classi:
codice:
public class TestFileSorgente {
    public static void main(String args[])
    {
        FileSorgente file = new FileSorgente("File.java",1,"public class TestFileSorgente ");
        System.out.println(file.getContenuto());
        
        file.aggiungiTesto("{");
        System.out.println(file.getContenuto());
        
        file.aggiungiTesto(null);
        System.out.println(file.getContenuto());
        
        file.aggiungiTesto("}",31);
        System.out.println(file.getContenuto());
        
        file.aggiungiTesto("// testo",31);
        System.out.println(file.getContenuto());
        
    }

}
codice:
import java.lang.String;

public class FileSorgente extends File
{
    private String contenuto;
    
    public FileSorgente(String nome, int tipo, String contenuto)
    {
        super(nome,tipo);
        setContenuto(contenuto);
    }
    
    public void setContenuto(String contenuto)
    {
        this.contenuto = contenuto;
    }
    
    public String getContenuto()
    {
        return contenuto;
    }

    public String aggiungiTesto(String testo) throws RuntimeException
    {
        if (contenuto == null)
        {
            contenuto = "";
        }
        if (testo == null)
        {
            throw new RuntimeException();
        }
        contenuto += testo;
        return contenuto;
    }
    
    public String aggiungiTesto(String testo, int posizione)
    {
        try
        {
            if (testo != null)
            {
                contenuto = contenuto.substring(0, posizione) + testo + contenuto.substring(posizione);
            }
        }
        catch (NullPointerException exc)
        {
            System.out.println("Il contenuto è null : " + exc.getMessage());
            contenuto = "" + testo;
        }
        catch (StringIndexOutOfBoundsException exc)
        {
            System.out.println("L'indice " + posizione + "non è valido : " + exc.getMessage());
            contenuto = (posizione < 0 ? testo + contenuto : contenuto + testo);
        }
        
        return contenuto;
    }
    
    
    public void cercaEsostituisci(String cercato, String parola)
    {
        String stringa = this.getContenuto();
        if(stringa.contains(cercato))
        {
            String risultato = stringa.replace(cercato,parola);
            this.setContenuto(risultato);
        }
        
    }
        
}
Veniamo a quello che vorrei capire:
1) Nel main è corretto che non ci siano blocchi try-catch perchè il main deve rimanere il più "pulito" possibile e quel tipo di controlli vanno effettuati dentro l'implementazione del metodo che si vuole tenere sotto controllo e non dove viene richiamato. Giusto?

2) Nel caso in cui io volessi creare un file senza contenuto per come ho fatto il metodo aggiungiTesto(testo,posizione) questo dovrebbe generare una NullPointerException perchè appunto il contenuto risulta null.
Se io però creassi un oggetto di tipo FileSorgente e non specificassi al momento dell'istanziazione la stringa del contenuto mi sarebbe subito segnalato come errore e non mi permetterebbe neanche di compilare. Quindi che senso ha inserire la gestione di una NullPointerException nel metodo aggiungiTesto(testo,posizione) se non riuscirei neanche a compilare il file a causa dell'errore?

3) Qual è la differenza tra la gestione delle eccezioni nel metodo aggiungiTesto(testo) e la gestione delle eccezioni nel metodo aggiungiTesto(testo,posizione)? Nel primo caso viene usato throws e throw mentre nel secondo i blocchi try-catch ma ad esempio non mi è chiaro dove viene catturata l'eccezione generata nel metodo aggiungiTesto(testo) visto che non c'è una catch.