When you create a interface you are defining a contract for what a class can do, without saying anything about how the class will do it. A interface is a contract. Interfaces can be implemented by any class from any inheritance tree, this lets you take radically different classes and give them a common characterstic. By defining a interface within the class you agree to provide the code for any of the interfaces methods, an interface generally has abstract methods (a abstract class can contain both abstract and non-abstract methods). There are many interfaces supplied by Java for example java.lang.Comparable, java.io.Serializable and java.util.List.
The rules of an interface are
Interface declaration | public abstract interface Rollable { ... } # should use the below declaration as the keyword abstract is # redundant, but this is acceptable interface Rollable { ... } # there is no need to specify the abstract or public keywords |
Method declaration | public interface Bounceable { Note: you do not need to specify the public abstract modifiers (now redundant), so both above methods are acceptable, all methods are public and abstract no matter what you see. |
Default method | interface Bounceable { default void defaultMethod() { System.out.println("This is an interface default method"); } } Note: default methods must be implemented and are not abstract but can be overriden, also becareful of implementing multiple default methods (with the same signature) from multiple interfaces, you will get a compiler error |
Interface Constants | public interface Bounceable { Note: by putting constants in an interface you are guaranteeing that any class implementing the interface will have access to the same constant. They are also used to associate values with easy names to remember. as with the same with methods you do not need to specify the public final static modifiers (now redundant), so both above declarations are acceptable, all constants are public final static no matter what you see. |
Implementing a interface | public class rubberBall implements Bounceable { Note: you are binded by a contract to supply the code for any of the interfaces methods, otherwise the compiler will complain. The signature of the method must be same as in the interface. Also a abstract class can implement a interface but at somepoint the interface methods code must be implemented to honour the binding contract. |
Using a static method in a interface | interface Bounceable { static String publicStaticMethod() { return "Interfaces public static method"; } } Note you can then use the public static method by calling Bounceable.publicStaticMethod(); |
Implementing multiple interfaces | public class rubberBall implements Bounceable, Serializable, Runnable { ... } |
Extending an interface | public interface Bounceable extends Moveable { ... } Note: an interface can itself extend another interface but never implement anything |
A complete example explaining implementing an interface
Implementing an interface | class arrayTest { public static void main(String[] args) { test t1 = new test(); t1.methodA(); } } class test implements inter1 { // enter into the interfaces contract, abstraction rules now apply interface inter1 { // 100% abstract class - all methods are abstract Note: this program will not compile as there are a number of errors. |
Distinguish class inheritance from interface inheritance including abstract classes
Here is a table of the differences between abstract class and an interface. If you want to provide common, implemented functionality among all implementations of your component, use an abstract class. Abstract classes allow you to partially implement your class, whereas interfaces contain no implementation for any members.
Abstract class | Interface |
---|---|
Abstract class can have abstract and non-abstract methods. | Interface can have only abstract methods. Since Java 8, it can have default and static methods also. |
Abstract class can define public, protected, package-private or private concrete methods | All abstract methods are public |
An abstract method must be declared abstract | If a method has no body by default its implicity abstract |
Abstract class doesn't support multiple inheritance. | Interface supports multiple inheritance. |
Abstract class can have final, non-final, static and non-static variables. | Interface has only public, static and final variables. |
Abstract class can provide the implementation of interface. | Interface can't provide the implementation of abstract class. |
The abstract keyword is used to declare abstract class. | The interface keyword is used to declare interface. |
An abstract class can extend another Java class and implement multiple Java interfaces. | An interface can extend another Java interface only. |
An abstract class can be extended using keyword "extends". | An interface can be implemented using keyword "implements". |
A Java abstract class can have class members like private, protected, etc. | Members of a Java interface are public by default. |
Declare and use List and ArrayList Instances
Declaration of java.util.list is an interface that extends the Collection interface. List is an ordered collection, you have control on where each element is inserted. Elements can be accessed by their index and you can search the list. Lists can have duplicate and null elements.
Declaration of java.util.ArrayList is a class that extends AbstractList and implements List among other interfaces. ArrayList is a resizeable array implementation of the List interface. This class is the same as Vector except that it is unsynchronized, also ArrayList does not support primitive data types, use primitive data wrappers instead.
Instantiation of ArrayList | ArrayList rawList = new ArrayList(List.of(1, 2, 3, 4, 5)); # This is a raw type of ArrayList ArrayList <String> stringArray = new ArrayList<String>(); # Using generics to set the data type ArrayList <String> stringArray = new ArrayList<String>(10); # You can set the capacity of the ArrayList, 10 in this example ArrayList <String> stringArray = new ArrayList<>(10); # You can use a blank diamond ArrayList <Integer> stringArray = new ArrayList<>(List.of(10, 20, 30)); # You can pass values into the ArrayList ArrayList <String> stringArray = new ArrayList<>(); # You dont have to specify the capacity |
Some ArrayList examples | integerArray.add(intNumber); # Add to end of the list integerArray.add(i, intNumber); # add element to specific index location integerArray.addAll(List.of(15,20,25); # add a list of int's to the end of a list stringArray.removeIf(s -> s.contains"_2")); # you can even use lambda expressions stringArray.removeAll(List.of("String_1", "String_2")); # you can pass Lists to ArrayList methods |
There are many methods that can be used for ArrayList most of which are on the List interface.
Type of Functionality | ArrayList methods |
Comparison | equals isempty |
Searches | contains containsAll indexOf lastIndexOf |
Data Manipulation | add addAll clear get hashCode remove removeAll replaceAll retainAll set size sort |
Data Transformation | copyOf (Java 10) iterator listIterator of (Java 9) spliterator (Java 9) subList toArray |
Although I am not covering the complete collections I give you the tables belows so that you can understand what is available and when you should use them.
The collections come in three basic flavors each having subflavors of Sorted, Unsorted, Ordered and Unordered
Ordered means that you iterate through the collection in a specific order (not random), for an example you would iterate through an array starting at index position 0, this does not means that the object you retrieve are in any sorted order.
Sorted means you retrieve the objects that are sorted naturally, what i mean here is Strings objects would be alphabetically ordered, int would be numerically ordered.
List (a list cares about the index) |
|
ArrayList | Think of this as a growable array, it is a ordered collection (uses a index) but it is not sorted, this interface implements a RandomAccess interface Choose this over a LinkedList when you need fast iteration but aren't as likely to be doing a lot of insertion and deletion |
Vector | Vector and Hashtable were the original collections. A Vector is the same as a ArrayList but a Vector methods are synchronized for thread safety. Vectors also implement a RandomAccess interface. Use a ArrayList if you don't need synchronization at it decreases performance. |
LinkedList | LinkedList is ordered by index position, like ArrayList but doubly-linked up. LinkedLists are ideal for stacks and queues, its also a good candidate for fast insertion and deletion |
Set (a set cares about the uniqueness) |
|
HashSet | A HashSet is an unsorted, unordered Set. It uses the hashcode of the object being inserted, so the better the hashcode the better performance you will get. Use this when you want a collection with no duplicates and you don't really care about the order. |
LinkedHashSet | A LinkedHashSet is an ordered version of a HashSet that maintains a doubly-linked List across all elements. use this collection when you care about the order |
TreeSet | It uses a Red-Black tree structure that guarantees that elements will be in ascending order, according to the natural order of the elements (String would be a,b,c,d,etc , int would be 1,2,3,4), there will also be no duplicates. |
Map (a map cares about unique identifiers) |
|
HashMap | The HashMap gives you an unsorted, unordered Map Use when you need a Map but don't care about the order, fast updates (key/value pairs), allows one null key and many null values. |
Hashtable | Hashtable is the synchronized version of a HashMap If you don't need synchronization then use a HashMap |
LinkedHashMap | LinkedHashMap maintains insertion order or last accessed. |
TreeMap | A TreeMap is a sorted Map by the natural order of elements |
A quick reference regarding collections
Class |
Map |
Set |
List |
Ordered |
Sorted |
HashMap | X |
No |
No |
||
Hashtable | X |
No |
No |
||
TreeMap | X |
Sorted |
By natural order or custom comparison rules |
||
LinkedHashMap | X |
By insertion order or last access order |
No |
||
HashSet | X |
No |
No |
||
TreeSet | X |
Sorted |
By natural order or custom comparison rules |
||
LinkedHashSet | X |
By insertion order or last access order |
No |
||
ArrayList | X |
By Index |
No |
||
Vector | X |
By Index |
No |
||
LinkedList | X |
By Index |
No |
Before Lambda expression, anonymous inner classes were the feature that enabled you to make your code more concise. Anonymous classes are like local classes, except that they do not have a name. You use them if you need to use a local class only once. Lambda expressions replace the bulkiness of anonymous inner classes.
Functional interfaces provide target types for lambda expressions and method references. Each functional interface has a single abstract method, called the function method for that functional interface, to which the lambda's expression's parameter and return types are matched or adapted. Functional interfaces can provide a target type in multiple contexts such as assignment context, method invocation or cast context.
Lambda Expression Syntax | Argument List Arrow Token Body (int x, int y) -> x + yParameters:
|
Valid Lambda Expression | () -> System.out.println("Hello") # No parameter syntax, () is required a -> a + 1 # Single parameter syntax, no parenthese required (a) -> a + 1 # Single parameter syntax, parenthese valid but optional (int a) -> a + 1 # Single parameter syntax, specifying data type (var a) -> a + 1 # Single parameter syntax with local varible type inference (int a, int b) -> a + b # Multiple parameter syntax with declared types, all must have a type (a, b) -> a + b # Multiple parameter syntax with no types, if one has not type all must have no types (var a, var b) -> a + b # Multiple parameter syntax the local variable type, if one has var type then all must have as well Note: parenthese are always required for m ultiple parameters () -> System.out.println("Hello") # Single line with a statement is valid for methods which have void return type () -> isTrue && isPlusible # Single line expression must be an expression which evaluates to the correct return type or covariant, if method has a return type. (a) -> { # Using return requires curly braces, all statements must terminate with a semi-colon, you can use local variables int count = 1; return a + count + 2; } Note: You cannot mix var data types with actual data types |
There are a number of Generic and Primitaive interfaces that statisfy common patterns and sveral of these are in the java.util.function package
Functional Interface Generic | Functional Interface Typed |
---|---|
UnaryOperator<T> | DoubleUnaryOperator IntUnaryOperator LongUnaryOperator |
BinaryOperator<T> | DoubleBinaryOperator IntBinaryOperator LongBinaryOperator |
Consumer<T> | DoubleConsumer IntConsumer LongConsumer |
Predicate<T> | DoublePredicate IntPredicate LongPredicate |
Supplier<T> | DoubleSupplier IntSupplier LongSupplier |
Function<T,R> | DoubleFunction<R> IntFunction<R> LongFunction<R> |
Below is a complete example of a few Lambda expressions
Lambda example | import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; public class SuppliedInterfaceTests { public static void main(String[] args) { // Set up some test data String[] dictionary = {"Angry", "Apple", "Art", "Ball", "Box", "Bump", "Cap", "Car", "Cone", "Dart", "Dog", "Duck"}; // -- Consumer Example // Method returns no result, just does something on // the parameter passed Consumer |