Advance Topics

Advanced Programming

SUT • Spring 2019

Contents

  • Enumerations

  • Static Import

  • Annotation

Enumerations

Enumerations

  • Suppose you have a class with a few instances

  • Example:

    • Student Type : <BS, MS, PhD>

    • SMS Status : <Sent, Delivered, Not Delivered, Not Sent>

    • Color : <Blue, Green, Black, Red>

  • How do you implement it?

    • The class should not be inherited

    • The instances are limited: no further instances

Example

final class Color{
    public static final Color Black = new Color(1);
    public static final Color Blue = new Color(2);
    public static final Color Green = new Color(3);
    public static final Color Red = new Color(4);

    private int color;
    private Color(int i) {
    	this.color = i;
    }
}

Java enum

  • Java introduces enumerations for this purpose

  • Enumerated Data Type

  • A simple class

  • enum keyword instead of class or interface

  • Comma seperated enum instances

  • enum instances are constant

  • enum Color {

  •         Black, Blue, Green, Red

  • }

Enum

enum Color {
    Black, Blue, Green, Red
}

final class Color{
  public static final Color Black = new Color();
  public static final Color Blue = new Color();
  public static final Color Green = new Color();
  public static final Color Red = new Color();
}

Enum Sample

enum Shape {
    Rectangle, Circle, Square
}

enum StudentType{
    BS, MS, PhD
}

Using Enums

Color color = Color.Black;
Shape shape = Shape.Circle;
show(shape, color);
...

private static void show (Shape shape, Color color) {
    //show a shape with this color
    ...
}

Enum Characteristics

  • enum types are implicitly final

    • Can not be a super-class

    • Because they declare constants that should not be modified

  • Instances are constants

    • enum constants are implicitly public, static and final

  • No new instances can be created

    • object  instantiation of enum types with operator new results in a compilation error.

Enum

  • Enum can be a more complex class

  • With many constructors

  • And fields

  • And methods

Example

enum Shape {
    Rectangle(1), Circle(2), Square(3);

    private int number;
    
    Shape(int i){
        number = i;
    }
    
    public int getNumber(){
        return number;
    }
}

Example

Shape shape = Shape.Circle;
print (shape.getNumber());

shape = Shape.valueOf("Rectangle");
print(shape.getNumber());

Shape[] shapesArray = Shape.values();
for (Shape s : shapesArray) {
    print(s.name());
}

try{
    shape = Shape.valueOf("Pyramid");
}catch(Exception exp){
    print("Pyramid is not included in Shape");
}

Static Import

  • In order to access static members

  • Qualify references with the class they came from.

  • For example:

    • double r = Math.sin(Math.PI * theta);

  • static import allows unqualified access to static members

  • without inheriting from the type containing the static members

    • import static java.lang.Math.PI;

  • or

    • import static java.lang.Math.*;

    • double r = sin(PI * theta);

Annotation

  • An annotation is a special form of metadata

  • Added to Java source code

  • Classes, methods, variables, parameters and packages may be annotated

  • Unlike Javadoc tags, Java annotations can be reflective

  • They can be embedded in class files (byte code)

  • May be retained by the Java VM at run-time

  • Example

    • @Override,   @Deprecated,   @ SuppressWarnings, …

Functional Programming

What is Functional Programming?

  • A style of programming that treats computation as the evaluation of mathematical functions

  • Eliminates side effects

  • Treats data as being immutable

  • Functions can take functions as arguments and return functions as results

  • Prefers recursion over explicit for-loops

Why do Functional Programming?

  • Allows us to write easier-to-understand, more declarative, more concise programs than imperative programming

  • Allows us to focus on the problem rather than the code

  • Facilitates parallelism

Java 8

  • Java 8 is the biggest change to Java since the inception of the language

  • Lambdas are the most important new addition

  • Java is playing catch-up: most major programming languages already have support for lambda expressions

  • A big challenge was to introduce lambdas without requiring recompilation of existing binaries

Benefits of Lambdas in Java 8

  • Enabling functional programming

  • Writing leaner more compact code

  • Facilitating parallel programming

  • Developing more generic, flexible and reusable APIs

  • Being able to pass behaviors as well as data to functions

Java 8 Lambdas

  • Syntax of Java 8 lambda expressions

  • Functional interfaces

  • Method references

  • Default methods

Example 1:

List<Integer> intSeq = Arrays.asList(1,2,3);

intSeq.forEach(x -> System.out.println(x));

Example 2:

List<Integer> intSeq = Arrays.asList(1,2,3);

intSeq.forEach(x -> {
   x += 2;
   System.out.println(x);
});

Example 3:

List<Integer> intSeq = Arrays.asList(1,2,3);

intSeq.forEach(x -> {
   int y = x * 2;
   System.out.println(y);
});

Example 4:

List<Integer> intSeq = Arrays.asList(1,2,3);

intSeq.forEach((Integer x -> {
   x += 2;
   System.out.println(x);
});

Implementation of Java 8 Lambdas

  • The Java 8 compiler first converts a lambda expression into a function

  • It then calls the generated function

  • For example, x -> System.out.println(x) could be converted into a generated static function

  •  

  •  

  •  

  • But what type should be generated for this function? How should it be called? What class should it go in?

public static void genName(Integer x) {
   System.out.println(x);
}

Functional Interfaces

  • Design decision: Java 8 lambdas are assigned to functional interfaces.

  • A functional interface is a Java interface with exactly one non-default method.  E.g.,

  •  
  •  
  •  

  • The package java.util.function defines many new useful functional interfaces.

public interface Consumer<T> {
   void accept(T t);
}

Assigning a Lambda to a Local Variable

public interface Consumer<T> {
  void accept(T t);
}

void forEach(Consumer<Integer> action {
  for (Integer i:items) {
    action.accept(t);
  }
}

List<Integer> intSeq = Arrrays.asList(1,2,3);

Consumer<Integer> cnsmr = x -> System.out.println(x);
intSeq.forEach(cnsmr);

Properties of the Generated Method

  • The method generated from a Java 8 lambda expression has the same signature as the method in the functional interface

  • The type is the same as that of the functional interface to which the lambda expression is assigned

  • The lambda expression becomes the body of the method in the interface

Method References

  • Method references can be used to pass an existing function in places where a lambda is expected

  • The signature of the referenced method needs to match the signature of the functional interface method

Summary of Method References

Method Reference Type Syntax Example
static ClassName::StaticMethodName String::valueOf
constructor ClassName::new ArrayList::new
specific object instance objectReference::MethodName x::toString
arbitrary object of a given type ClassName::InstanceMethodName Object::toString

Conciseness with Method References

  • We can rewrite the statement

  • intSeq.forEach(x -> System.out.println(x));

  •  

  • more concisely using a method reference

  • intSeq.forEach(System.out::println);

Stream API

  • The new java.util.stream package provides utilities to support functional-style operations on streams of values.

  • A common way to obtain a stream is from a collection:

  •         Stream<T> stream = collection.stream();

  • Streams can be sequential or parallel.

  • Streams are useful for selecting values and performing actions on the results.

Stream Operations

  • An intermediate operation keeps a stream open for further operations. Intermediate operations are lazy.

  • A terminal operation must be the final operation on a stream. Once a terminal operation is invoked, the stream is consumed and is no longer usable.

Example Intermediate Operations

  • filter excludes all elements that don’t match a Predicate.

  • map performs a one-to-one transformation of elements using a Function.

Cont.

  • A stream pipeline has three components:

    • A source such as a Collection, an array, a generator function, or an IO channel;

    • Zero or more intermediate operations; and

    • A terminal operation

Stream Example

int sum = widgets.stream()
	.filter(w -> w.getColor() == RED)
	.mapToInt(w -> w.getWeight())
	.sum();

Example

List<Integer> list = Arrays.asList(1,2,3);
int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sum);

Title Text

Advanced Topics

By Behnam Hatami

Advanced Topics

Advanced Topics / Advanced Programming Course @ SUT, Spring 2019

  • 1,436