Informatics Practices for Class XI (CBSE)/Programming fundamentals

Note: Based on the Java Overview chapter of the Java Programming book.

Before Java emerged as a programming language, C++ was the dominant player in the trade. The primary goals that the developers of Java faced was to create a language that could tackle most of the things that C++ offered while getting rid of some of the more tedious tasks that came with the earlier languages.

The new features and upgrades included into Java changed the face of programming environment and gave a new definition to Object Oriented Programming. But unlike its predecessors, Java needed to be bundled with standard functionality and be independent of the host platform. This is further explained in this section.

The primary goals in the creation of the Java language:

  • It is simple.
  • It is object-oriented.
  • It is independent of the host platform
  • It contains language facilities and libraries for networking.
  • It is designed to execute code from remote sources securely.

The Java language introduces some new features that did not exist in other languages like C and C++.

The introduction of those features are the subject of this page.

Earlier programming languages

edit

Computer hardware went through a performance and price revolution in the 1980s and 1990s. Better, faster hardware was available at lesser price and the demand for big and complex software exponentially increased. To accommodate the demand, new development technologies were invented.

The C language developed in 1972 by Dennis Ritchie had taken a decade to become the most popular language amongst programmers. But, with time programmers found that programming in C became tedious with its structural syntax. [1] Although, people attempted solving this problem, it would be later that a new development philosophy was introduced, one named Object-Oriented Programming (OOP in short). With OOP, a person may write a certain code which may be reused later without rewriting the code over and over again. In 1979, Bjarne Stroustrup developed C++, an enhancement to the C language with included OOP fundamentals and features.

Platform dependence and zero-modularity

edit

However, over time, people began to realize the problems with the architecture of the language. For one, the language produced different results/output for different platforms. C/C++ applications only adhered to platforms they were targeting and would not work on others. A certain program built for a certain platform would only target that specific platform or hardware. This close-knitted integration with the hardware posed greater vulnerability risks.

 

Note here that when a certain code is compiled into an executable format. The executable can not be changed dynamically. It would need to be recompiled from the changed code for the changes to be reflected in the finished executable. Modularity (dividing code into modules) is evidently not present in Java's predecessors. If instead of a single executable, the output application was in the form of modules, one can easily change a single module and review changes in the application, but rather in C/C++, a slight change in code required the whole application to be recompiled.

Unsafe code

edit

With the high-level of control built into the language to manipulate hardware, a programmer could access almost any resource, either hardware or software on the system. This was to be one of the languages' strong points, but this very flexibility led to confusion and complex programming practices. Memory leaks became a regular nuisance in instances where the programmers had to manually attempt at using the system's memory resources.

Now memory resources or buffers have a peculiar way of working. Once a buffer is filled with data, it needs to be cleaned up after there is no use for its content. If a programmer forgets to clean it in his/her code, the memory is easily overloaded. Programming in C/C++ languages became tedious and unsafe because of these very quirks and programs built in the languages were prone to memory leakages and sudden system crashes, sometimes even harming the hardware itself.

Non-standardization and complexity

edit

C++ was built atop the C language and as a result different ways doing the same thing became evident in the language. For instance, creating an object could be done in three different ways in C++. Furthermore, the language did not come with a standard library bundled with its compilers and rather relied on resources created by other programmers with code which rarely fit together.

Networking capabilities

edit

However powerful, the predecessors of Java lacked a standard feature to network with other computers, and usually relied on the platforms intricate networking capabilities. With almost all network protocols being standardized, the creators of Java technology wanted this to be a flagship feature of the language while keeping true to the spirit of earlier advances made towards standardizing Remote Procedure Call. Another feature that the Java team focused on was its integration in the World Wide Web and the Internet.

Agenda for the new language

edit

Keeping all of the above in mind, the developers of Java created a list of features tackling these problems. In their opinion, Java should ...

  • .. be simple and gather tested fundamentals and features from the earlier languages in it,
  • .. have standard sets of APIs with basic and advanced features bundled with the language,
  • .. get rid of concepts requiring direct manipulation of hardware (in this case, memory) to make the language safe,
  • .. be platform independent and may written for every platform once (giving birth to the WORA idiom),
  • .. be able to manipulate network programming out-of-the-box,
  • .. be embeddable in web browsers, and ...
  • .. have the ability for a single program to multi-task and do multiple things at the same time.
  • Simple syntax, simple features. Those features that could be abused, by a programmer, were not added to the language. Those are:
    • Operator overloading
    • Multiple inheritance
    • Memory allocation (use of automatic garbage collection)
    • Friend classes (access an other object private members)
    • Force exception handling (programmer must handle exception or declare that the user must handle it, someone must handle it)
    • Automatic initializations (to give consistent behavior)
    • Restrictions of explicit type casting (related to memory management)
  • Platform Independence (run everywhere concept)
    • Compile to intermediate byte code that executed by a Java Virtual Machine
  • Network programming
    • Be able to download code from remote server and execute that code during runtime
    • Creates of the Applet concept (Applets can run in the client browser program)
  • Built in thread, multitasking capabilities to the language
    • Ease of multitasking (other languages needed third party libraries to do that)
  • Platform independent Graphical User Interface (GUI)
    • AWT (Contains widgets that most Operating system supports)
    • Swing (Added later)

Java was released in 1995, the time when the Internet started became available to the public. The promise of Java was in the client browser-side. The Java code would be downloaded and executed as Java applets in the client browser program.

Then the focus was moved to the server side. Java extensions were added to the JDK, it is called J2EE:

  • Servlet execution - (Alternative to CGI programs)
  • JSP, Java Server Pages - (Embed Java Code in HTML)
  • EJB - (Distributed object execution)

Dynamic class loading

edit

In conventional languages like C and C++, all code had to be compiled and linked to one executable program, before execution. In Java, classes are compiled as needed. If a class is not needed during an execution phase, that class is not even compiled into byte code.

This feature comes in handy especially in network programming when we do not know, beforehand, what code will be executed. A running program could load classes from the file system or from a remote server.

Also this feature makes it possible that a Java program could in theory alter their own code during execution, to do some self learning behavior. It would be more realistic to image however, that a Java program which generate Java code, before execution, then that code would be executed. With some feedback mechanism, next time the generated code could differ, thus it could improve in time.

Automatic memory garbage collection

edit

In conventional languages like C and C++, the programmer has to make sure that all memory that was allocated are freed. Freeing memory is particularly important in servers, since it has to run without stopping for days. If a piece of memory is not freed after use, and the server just keeps allocating memory, that memory leak can take down the server.

In Java, freeing up memory is taken out from the programmers hand. The Java Virtual Machine keeps track all of the used memory. When the memory is not used any more, it is automatically freed up. A separate task is running at the background by the JVM, freeing up unreferenced, unused memory. That task is called the "Garbage Collector".

The "Garbage Collector" is always running. This automatic memory garbage collection feature makes it easy to write robust server side programs in Java. The only thing the programmer has to watch for is the speed of object creation. If the application is creating objects faster than the "Garbage Collector" can free them, then that can cause memory problems. Depending on how the JVM is configured, the application either can run out of memory by throwing the NotEnoughMemoryException, or can halt to give time for the "Garbage Collector" to do its job.

Error handling

edit

For more info. see: Java Programming/Exceptions

The old way of error handling was to let each function return an error code then let the caller check what was returned. The problem with this method was that if the return code was full of error-checking codes, this got in the way of the original one that was doing the actual work, which in turn did not make it very readable.

The new way of error handling is when functions/methods do not return error codes. When there is an error an exception is thrown. The exceptions can be handled by the catch keyword at the end of a try block. This way, the code that is doing the actual work does not need to be mangled with error checking codes, thus making the code more readable. This new way of error handling is called Exception handling.

Exception handling was also added to C++. However, there are two differences between Java and C++ Exception handling.

  • In Java, the exception that is thrown is a Java object like any other object in Java. It only has to implement Throwable interface.
  • The compiler checks whether an exception was caught or not. The compiler gives an error if a there is no catch block for a thrown exception.

Platform independence

edit

Platform independence means that programs written in the Java language must run similarly on diverse hardware. One should be able to write a program once and run it anywhere. This is achieved by compiling Java language code "halfway" to bytecode--simplified virtual machine instructions that conform to a set standard. The code is then run on a Java virtual machine, a program written in native code on the host hardware that translates generic Java bytecode into usable code on the hardware. Further, standardized libraries are provided to allow access to features of the host machines (such as graphics and networking) in unified ways. The Java language also includes support for multi-threaded programs--a necessity for many networking applications.

The first implementations of the language used an interpreted virtual machine to achieve portability, and many implementations still do. These implementations produce programs that run more slowly than the fully-compiled programs created by the typical C++ compiler and some later Java language compilers, so the language suffered a reputation for producing slow programs. More recent implementations of the Java VM produce programs that run much faster, using multiple techniques.

The first of these is to simply compile directly into native code like a more traditional compiler, skipping bytecode entirely. This achieves great performance, but at the expense of portability. This is not really used any more.

Another technique, the just-in-time compiler or "JIT", compiles the Java bytecode into native code at the time the program is run, and keep the compiled code to be used again and again. More sophisticated VMs even use dynamic recompilation, in which the VM can analyze the behavior of the running program and selectively recompile and optimize critical parts of the program. Both of these techniques allow the program to take advantage of the speed of native code without losing portability.

Portability is a technically difficult goal to achieve, and Java's success at that goal is a matter of some controversy. Although it is indeed possible to write programs for the Java platform that behave consistently across many host platforms, the large number of available platforms with small errors or inconsistencies led some to parody Sun's "Write once, run anywhere" slogan as "Write once, debug everywhere".

Platform independent Java is, however, very successful with server side applications, such as web services, servlets, or Enterprise Java Beans.

Java also made progress on the client side, first it had Abstract Window Toolkit(AWT), then Swing, and the most recent client side library is the Standard Widget Toolkit(SWT). It is interesting to see how they tried to handle the two opposing consuming forces. Those are :

Efficient, fast code; port to most popular hardware (write once, test anywhere)
Use the underlying native subroutine to create a GUI component. This approach was taken by AWT, and SWT.
Portability to any hardware where JVM ported(write once, run anywhere)
To achieve this to the latter, the Java toolkit should not rely on the underlying native user interface. Swing took this approach.

It is interesting to see how the approach was switched back and forth. AWT - Swing - SWT.

Secure execution of remote code

edit

The Java platform was one of the first systems to provide wide support for the execution of code from remote sources. The Java language was designed with network computing in mind.

An applet could run within a user's browser, executing code downloaded from a remote HTTP server. The remote code runs in a highly restricted "sandbox", which protects the user from misbehaving or malicious code; publishers could apply for a certificate that they could use to digitally sign applets as "safe", giving them permission to break out of the sandbox and access the local file system and network, presumably under user control.

Object orientation

edit

Object orientation ("OO"), refers to a method of programming and language technique. The main idea of OO is to design software around the "things" (i.e. objects) it manipulates, rather than the actions it performs.

As the hardware of the computer advanced, it brought about the need to create better software techniques to be able to create ever increasing complex applications. The intent is to make large software projects easier to manage, thus improving quality and reducing the number of failed projects. Object oriented solution is the latest software technique.

Assembly languages
Software techniques started with the assembly languages, that was close to machine instruction and was easy to convert executable code. Each hardware had its own assembly language. Assembly language contains low level instructions like move data from memory to hardware registers, do arithmetic operations, and move data back to memory. Programmers had to know the detailed architecture of the computer in order to write programs.
Procedural languages
After the assembly languages, high level languages were developed. Here the language compiler is used to convert the high level program to machine instructions, freeing up the programmers the burden of knowing the computer hardware architecture. To promote the re-use of code, and to minimize the use of GOTO instruction, "procedural" techniques were introduced. This simplified the creation and maintenance of software control flow, but they left out the organization of data. It became a nightmare to debug and maintain programs having many global variables. Global variables contain data that can be modified anywhere in the application.
Object oriented languages
In OO languages, data is taken seriously with information hiding. Procedures were replaced by Objects. Objects contain data as well as control flow. Our thinking has to shift from procedures to interaction between objects.

Evaluation

edit

'In most people's opinions, Java technology delivers reasonably well on all' these goals. The language is not, however, without drawbacks. Java tends to be more high-level than similar languages (such as C++), which means that the Java language lacks features such as hardware-specific data types, low-level pointers to arbitrary memory addresses, or programming methods like operator overloading. Although these features are frequently abused or misused by programmers, they are also powerful tools. However, Java technology includes Java Native Interface (JNI), a way to call native code from Java language code. With JNI, it is still possible to use some of these features.

Some programmers also complain about its lack of multiple inheritance, a powerful feature of several object-oriented languages, among others C++. The Java language separates inheritance of type and implementation, allowing inheritance of multiple type definitions through interfaces, but only single inheritance of type implementation via class hierarchies. This allows most of the benefits of multiple inheritance while avoiding many of its dangers. In addition, through the use of concrete classes, abstract classes, as well as interfaces, a Java language programmer has the option of choosing full, partial, or zero implementation for the object type he defines, thus ensuring maximum flexibility in application design.

There are some who believe that for certain projects, object orientation makes work harder instead of easier. This particular complaint is not unique to the Java language but applies to other object-oriented languages as well.

Note for C programmers

edit

Tools exist to aid the migration of existing projects from C to Java. In general, automated translator tools fall into one of two distinct kinds:

  • One kind converts C code to Java byte code. It is basically a compiler that creates byte code. It has the same steps as any other C compiler. See also C to Java JVM compilers.
  • The other kind translates C code to Java source code. This type is more complicated and uses various syntax rules to create readable Java source code. This option is best for those who want to move their C code to Java and stay in Java. [example needed]

Invoking C programs from Java applications

edit

You can use Runtime.exec method to invoke a program from within a running Java application. Runtime.exec also allows you to perform operations related to the program, such as control the program's standard input and output, wait until it completes execution, and get its exit status.

Here's a simple C application that illustrates these features. This C program will be called from Java:

#include <stdio.h>

int main() {
    printf("testing\n");
    return 0;
}

This application writes a string "testing" to standard output, and then terminates with an exit status of 0. To execute this simple program within a Java application, compile the C application:

$ cc test.c -o test

Then invoke the C program using this Java code:

import java.io.*;
import java.util.ArrayList;

public class ExecDemo 
{
    static public String[] runCommand(String cmd) throws IOException 
    {
        // --- set up list to capture command output lines ---
        ArrayList list = new ArrayList();

        // --- start command running
        Process proc = Runtime.getRuntime().exec(cmd);

        // --- get command's output stream and
        // put a buffered reader input stream on it ---
        InputStream istr = proc.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(istr));

        // --- read output lines from command
        String str;
        while ((str = br.readLine()) != null)
            list.add(str);

        // wait for command to terminate
        try {
            proc.waitFor();
        }
        catch (InterruptedException e) {
            System.err.println("process was interrupted");
        }

        // check its exit value
        if (proc.exitValue() != 0)
            System.err.println("exit value was non-zero");

        // close stream
        br.close();

        // return list of strings to caller
        return (String[])list.toArray(new String[0]);
    }

    public static void main(String args[]) throws IOException {
        try {

            // run a command
            String outlist[] = runCommand("test");

            // display its output
            for (int i = 0; i < outlist.length; i++)
                System.out.println(outlist[i]);
        }
        catch (IOException e) {
            System.err.println(e);
        }
    }
}

The demo calls a method runCommand to actually run the program.

 String outlist[] = runCommand("test");

This method hooks an input stream to the program's output stream, so that it can read the program's output, and save it into a list of strings.

 
 InputStream istr = proc.getInputStream();
 BufferedReader br = new BufferedReader(new InputStreamReader(istr));  
                
 String str;
 while ((str = br.readLine()) != null)
     list.add(str);
  1. Structural syntax is a linear way of writing code. A program is interpreted usually at the first line of the program's code until it reaches the end. One can not hook a later part of the program to an earlier one. The flow follows a linear top-to-bottom approach.