Simple tool to save a web page's source. A result of trying to learn and apply an MVC approach. The FXML is generated via Scene Builder, but included for completion.I welcome any general feedback on how to improve anything but in particular:There are many exceptions, current impression is that current handling is not ideal.What is the conventional wisdom on handling a plethora of io/connection errors?API and methods utilized in reading and writing were changed several times. Thanks to @rolfl's answer to a related question, currently refactored to employ Java 8 streams, is this the most appropriate for purpose? Can it be cleaner? Faster?Any conventions that should be followed, especially in regards to MVC, FXML.The following is the source, with a line in the main class commented out so this may be executed if desired.Main Class:import java.io.IOException;import javafx.application.Application;import javafx.fxml.FXMLLoader;import javafx.scene.Parent;import javafx.scene.paint.Color;import javafx.scene.Scene;import javafx.scene.image.Image;import javafx.stage.Stage;public class HTMLSave extends Application {    public static void main(String[] args) {        launch(args);    }    @Override    public void start(Stage stage) {        Parent root = null;        try {            root = FXMLLoader.load(getClass().getResource(HTML_Save.fxml));        } catch (IOException ioe) {            System.err.println(Could not load FXML);        }        Scene scene = new Scene(root, Color.TRANSPARENT);        scene.getStylesheets().add(html-save.css);        stage.setScene(scene);        stage.setTitle(HTML Saver);        //stage.getIcons().add(new Image(getClass().getResourceAsStream(icon.png)));        stage.show();    }}Controller Class:import java.awt.Desktop;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileOutputStream;import java.io.InputStreamReader;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.UncheckedIOException;import java.io.Writer;import java.net.URL;import java.util.ResourceBundle;import java.util.stream.Collectors;import javafx.concurrent.Task;import javafx.fxml.FXML;import javafx.fxml.Initializable;import javafx.scene.Cursor;import javafx.scene.control.Alert;import javafx.scene.control.Alert.AlertType;import javafx.scene.control.Button;import javafx.scene.control.ProgressBar;import javafx.scene.control.TextField;public class HTMLSaveController implements Initializable {    @FXML    private Button saveButton;    @FXML    private Button openButton;    @FXML    private TextField htmlField;    @FXML    private TextField filenameField;    @FXML    private ProgressBar progressBar;    private String destinationFile;    @Override    public void initialize(URL location, ResourceBundle resources) {        System.out.println(HTML Saver view successfully loaded.);    }    public void handleSaveRequest() {        String filename = filenameField.getText();        String url = htmlField.getText();        if (url.isEmpty()) {            errorAlert(URL missing, Please paste in website address);        } else if (filename.isEmpty()) {            errorAlert(No filename, Please enter a file name to save html);        } else {            destinationFile = filename + .html;            try (Writer destination = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destinationFile), UTF-8))) {                savePageSource(url, destination);            } catch (IOException ioe) {                System.err.println(Could not write to  + filename + '.');            }        }    }    public void handleOpenRequest() {        try {            Desktop.getDesktop().open(new File(destinationFile));        } catch (IOException ioe) {            System.err.println(destinationFile +  not found.);        }    }    private void errorAlert(String message, String infoMessage) {        Alert alert = new Alert(AlertType.ERROR);        alert.setTitle(Error);        alert.setHeaderText(message);        alert.setContentText(infoMessage);        alert.showAndWait();    }    private void savePageSource(String url, Writer destination) throws IOException {        Task saveTask = new Task() {            @Override            protected Void call() throws IOException {                updateProgress(0, 100);                openButton.setDisable(true);                try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(url).openStream()))) {                    progressBar.setCursor(Cursor.WAIT);                    destination.write(reader.lines().collect(Collectors.joining(\n)));                } catch (IOException ioe) {                    throw new UncheckedIOException(ioe);                }                 progressBar.setCursor(Cursor.DEFAULT);                updateProgress(1, 1);                openButton.setDisable(false);                return null;            }        };        progressBar.progressProperty().bind(saveTask.progressProperty());        Thread savingThread = new Thread(saveTask);        savingThread.start();        try {            savingThread.join();        } catch (InterruptedException ie) {            ie.printStackTrace();        }    }}CSS:.label {    -fx-text-fill: rgb(166, 226, 46);    -fx-font-weight: bold;}.button {    -fx-text-fill: rgb(166, 226, 46);    -fx-background-color: rgb(39, 40, 34);    -fx-border-radius: 20;    -fx-background-radius: 20;    -fx-padding: 5;}.button:hover {    -fx-text-fill: rgb(249, 38, 114);}.root{    -fx-font-family: Courier New;    -fx-background: rgb(61, 61, 59);    -fx-base: rgb(39, 40, 34);}.text-field:focused {    -fx-background-color: #a9a9a9 , white , white;    -fx-background-insets: 0 -1 -1 -1, 0 0 0 0, 0 -1 3 -1;}.progress-bar > .bar {    -fx-background-color: linear-gradient(        from 0px .75em to .75em 0px,        repeat,        rgb(253, 151, 31) 0%,        rgb(253, 151, 31) 49%,        derive(rgb(253, 151, 31), 30%) 50%,        derive(rgb(253, 151, 31), 30%) 99%    );}FXML:<?xml version=1.0 encoding=UTF-8?><?import javafx.scene.*?><?import javafx.scene.text.*?><?import javafx.scene.control.*?><?import java.lang.*?><?import javafx.scene.layout.*?><GridPane maxHeight=-Infinity maxWidth=-Infinity minHeight=-Infinity minWidth=-Infinity prefHeight=174.0 prefWidth=474.0 xmlns=http://javafx.com/javafx/8.0.40 xmlns:fx=http://javafx.com/fxml/1 fx:controller=HTMLSaveController>  <columnConstraints>    <ColumnConstraints hgrow=SOMETIMES maxWidth=309.0 minWidth=10.0 prefWidth=203.0 />    <ColumnConstraints hgrow=SOMETIMES maxWidth=398.0 minWidth=10.0 prefWidth=271.0 />  </columnConstraints>  <rowConstraints>    <RowConstraints maxHeight=121.0 minHeight=10.0 prefHeight=114.0 vgrow=SOMETIMES />    <RowConstraints maxHeight=181.0 minHeight=10.0 prefHeight=129.0 vgrow=SOMETIMES />    <RowConstraints maxHeight=293.0 minHeight=10.0 prefHeight=121.0 vgrow=SOMETIMES />  </rowConstraints>   <children>      <Button fx:id=saveButton defaultButton=true mnemonicParsing=false onAction=#handleSaveRequest prefHeight=39.0 prefWidth=73.0 text=Save textFill=#36d721 GridPane.columnIndex=1 GridPane.halignment=RIGHT GridPane.rowIndex=2 GridPane.valignment=TOP>         <font>            <Font size=18.0 />         </font>         <cursor>            <Cursor fx:constant=HAND />         </cursor></Button>      <Label text=Paste Address: >         <font>            <Font size=20.0 />         </font></Label>      <Label text=Enter Filename:  GridPane.rowIndex=1>         <font>            <Font size=20.0 />         </font></Label>      <TextField fx:id=htmlField GridPane.columnIndex=1 />      <TextField fx:id=filenameField GridPane.columnIndex=1 GridPane.rowIndex=1 />      <VBox prefHeight=123.0 prefWidth=205.0 GridPane.rowIndex=2>         <children>            <Button fx:id=openButton disable=true mnemonicParsing=false onAction=#handleOpenRequest prefHeight=39.0 prefWidth=81.0 text=Open textFill=#6f2929>               <font>                  <Font size=18.0 />               </font>               <cursor>                  <Cursor fx:constant=HAND />               </cursor>            </Button>            <ProgressBar fx:id=progressBar prefWidth=200.0 progress=0.0>               <cursor>                  <Cursor fx:constant=DEFAULT />               </cursor>            </ProgressBar>         </children>      </VBox>   </children></GridPane>The result:
Stylishly saving source
java;mvc;error handling;xml;javafx