4
\$\begingroup\$

This is my first experiment that uses a network API and connects to the internet. I tried to write a program that gives you an article of wikipedia directly by typing the name.

You can get an article like this:

java ArticleSupplier computer science
java ArticleSupplier captain underpants

If you have tips for me how to improve the performance or how to make a better structure, I would be thankful!

import java.util.Scanner;
import java.io.InputStream;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;

public class ArticleSupplier {
    private String nameOfArticle; // will be the name of the created document
    private String urlName;
    private URL url;
    private String article;

    public ArticleSupplier(String[] urlComponents) {
        // initialize article
        article = "";

        // initialize urlName and nameOfArticle
        urlName = "https://en.wikipedia.org/wiki/";
        nameOfArticle = "";
        for(int i = 0; i < urlComponents.length; i++) {
            urlName += urlComponents[i];
            urlName += "_";

            nameOfArticle += urlComponents[i];
            nameOfArticle += " ";
        }
        urlName = urlName.substring(0, urlName.length() - 1);
        nameOfArticle = nameOfArticle.substring(0, nameOfArticle.length() - 1);

        // initialize url
        try {
            url = new URL(urlName);
        } catch(MalformedURLException e) {
            e.printStackTrace();
        }
    }

    public void getArticle() {
        try(InputStream inputStream = url.openStream(); Scanner scanner = new Scanner(inputStream)) {
            while(scanner.hasNext()) {
                article += scanner.next() + "\n";
            }
        } catch(IOException e) {
            System.out.println(e);
        }
    }

    public void saveAsHTML() {
        String filename = nameOfArticle + ".html";
        try(FileWriter fileWriter = new FileWriter(filename);
            BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)) {
            bufferedWriter.write(article);
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ArticleSupplier as = new ArticleSupplier(args);
        as.getArticle();
        as.saveAsHTML();
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Just a minor point: I prefer "top down" source code in Java. Placing main at the end of a source listing is older Pascal style and looks a bit odd in Java. (And we only did that because older compilers couldn't handle forward references.) \$\endgroup\$ – markspace Dec 18 '17 at 18:35
  • 1
    \$\begingroup\$ Also, using Scanner which uses regex under the hood is going to be somewhat inefficient. Look at just using a BufferedReader directly. Also look at setting the buffer size to something large, like 64k bytes. However, Wikipedia articles tend to be somewhat short (like, less than 1 megabyte) and so the actual performance of reading a network socket may not matter much here. (Sorry for the short comments, I don't have a lot of time atm.) \$\endgroup\$ – markspace Dec 18 '17 at 18:44
2
\$\begingroup\$

Advice 1

urlName = "https://en.wikipedia.org/wiki/";

I suggest you make that magic string a static constant:

private static final String WIKIPEDIA_MAIN_URL =
        "https://en.wikipedia.org/wiki/";

Advice 2

for(int i = 0; i < urlComponents.length; i++) {
    ...

According to (common) Java coding conventions there must be a single space between for and the opening brace:

for (int i ...
   ^

Advice 3

for (int i = 0; i < urlComponents.length; i++) {

may be written as

for (String urlComponent : urlComponents) {

Advice 4

for(int i = 0; i < urlComponents.length; i++) {
    urlName += urlComponents[i];
    urlName += "_";

    nameOfArticle += urlComponents[i];
    nameOfArticle += " ";
}
urlName = urlName.substring(0, urlName.length() - 1);
nameOfArticle = nameOfArticle.substring(0, nameOfArticle.length() - 1);

You are essentially repeating yourself; I would do this instead:

StringBuilder stringBuilder = new StringBuilder();
String separator = "";

for (String urlComponent : urlComponents) {
    stringBuilder.append(separator).append(urlComponent);
    separator = "_";
}

this.articleName = stringBuilder.toString();
String urlName = WIKIPEDIA_MAIN_URL + stringBuilder.toString();

Advice 5

public void getArticle() {
    try(InputStream inputStream = url.openStream(); Scanner scanner = new Scanner(inputStream)) {
        while(scanner.hasNext()) {
            article += scanner.next() + "\n";
        }
    } catch(IOException e) {
        System.out.println(e);
    }
}

Why read one "word" at a time when you can read an entire line. Also, whenever building such strings, StringBuilder will be much more efficient:

public void getArticle() {
    StringBuilder stringBuilder = new StringBuilder();

    try (Scanner scanner = new Scanner(url.openStream())) {
        while (scanner.hasNextLine()) {
            stringBuilder.append(scanner.nextLine()); // <-- note the builder
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    this.article = stringBuilder.toString();
}

Alternative implementation

Gathering all the advices, I had this in mind:

import java.util.Scanner;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;

public class ArticleSupplier {

    private static final String WIKIPEDIA_MAIN_URL =
            "https://en.wikipedia.org/wiki/";

    private String articleName;
    private URL url;
    private String article;

    public ArticleSupplier(String[] urlComponents) {
        StringBuilder stringBuilder = new StringBuilder();
        String separator = "";

        for (String urlComponent : urlComponents) {
            stringBuilder.append(separator).append(urlComponent);
            separator = "_";
        }

        this.articleName = stringBuilder.toString();
        String urlName = WIKIPEDIA_MAIN_URL + stringBuilder.toString();

        try {
            this.url = new URL(urlName);
        } catch(MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

    public void getArticle() {
        StringBuilder stringBuilder = new StringBuilder();

        try (Scanner scanner = new Scanner(url.openStream())) {
            while (scanner.hasNextLine()) {
                stringBuilder.append(scanner.nextLine());
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        this.article = stringBuilder.toString();
    }

    public void saveAsHTML() {
        String filename = articleName + ".html";

        try (BufferedWriter writer =
                new BufferedWriter(new FileWriter(filename))) {
            writer.write(article);
        } catch(IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ArticleSupplier as = new ArticleSupplier(args);
        as.getArticle();
        as.saveAsHTML();
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.