[ This is a content summary only. Visit our website http://ift.tt/1b4YgHQ for full links, other content, and more! ]
by Web Desk via Digital Information World
"Mr Branding" is a blog based on RSS for everything related to website branding and website design, it collects its posts from many sites in order to facilitate the updating to the latest technology.
To suggest any source, please contact me: Taha.baba@consultant.com
Some ideas for multi-layered SVG shape overlays that get generated dynamically with adjustable properties for a variety of effects.
Neat animations as you scroll this dark-schemed One Pager for Whiteline Festival – an event celebrating audiovisual art, digital culture and the VJ community.
Java 8 was a huge step forward for the programming language and now, with the release of Android Studio 3.0, Android developers finally have access to built-in support for some of Java 8’s most important features.
In this three-part series, we’ve been exploring the Java 8 features you can start using in your Android projects today. In Cleaner Code With Lambda Expressions, we set up our development to use the Java 8 support provided by Android’s default toolchain, before taking an in-depth look at lambda expressions.
In this post, we’ll look at two different ways that you can declare non-abstract methods in your interfaces (something that wasn’t possible in earlier versions of Java). We'll also answer the question of, now that interfaces can implement methods, what exactly is the difference between abstract classes and interfaces?
We’ll also be covering a Java 8 feature that gives you the freedom to use the same annotation as many times as you want in the same location, while remaining backwards compatible with earlier versions of Android.
But first, let’s take a look at a Java 8 feature that’s designed to be used in combination with the lambda expressions we saw in the previous post.
In the last post, you saw how you can use lambda expressions to remove lots of boilerplate code from your Android applications. However, when a lambda expression is simply calling a single method that already has a name, you can cut even more code from your project by using a method reference.
For example, this lambda expression is really just redirecting work to an existing handleViewClick method:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(view -> handleViewClick(view));
}
private void handleViewClick(View view) {
}
In this scenario, we can refer to this method by name, using the :: method reference operator. You create this kind of method reference, using the following format:
Object/Class/Type::methodName
In our Floating Action Button example, we can use a method reference as the body of our lambda expression:
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(this::handleViewClick); }
Note that the referenced method must take the same parameters as the interface—in this instance, that’s View.
You can use the method reference operator (::) to reference any of the following:
If you have a lambda expression that calls a static method:
(args) -> Class.staticMethod(args)
Then you can turn it into a method reference:
Class::staticMethodName
For example, if you had a static method PrintMessage in a MyClass class, then your method reference would look something like this:
public class myClass {
public static void PrintMessage(){
System.out.println("This is a static method");
}
}
public static void main(String[] args) {
Thread thread = new Thread(myClass::PrintMessage);
thread.start();
}
}
This is an instance method of an object that’s known ahead of time, allowing you to replace:
(arguments) -> containingObject.instanceMethodName(arguments)
With:
containingObject::instanceMethodName
So, if you had the following lambda expression:
MyClass.printNames(names, x -> System.out.println(x));
Then introducing a method reference would give you the following:
MyClass.printNames(names,System.out::println);
This is an instance method of an arbitrary object that will be supplied later, and written in the following format:
ContainingType::methodName
Constructor references are similar to method references, except that you use the keyword new to invoke the constructor. For example, Button::new is a constructor reference for the class Button, although the exact constructor that’s invoked depends on the context.
Using constructor references, you can turn:
(arguments) -> new ClassName(arguments)
Into:
ClassName::new
For example, if you had the following MyInterface interface:
public Interface myInterface{
public abstract Student getStudent(String name, Integer age);
}
Then you could use constructor references to create new Student instances:
myInterface stu1 = Student::new;
Student stu = stu1.getStudent("John Doe", 27);
It’s also possible to create constructor references for array types. For example, a constructor reference for an array of ints is int[]::new.
Prior to Java 8, you could only include abstract methods in your interfaces (i.e. methods without a body), which made it difficult to evolve interfaces, post-publication.
Every time you added a method to an interface definition, any classes that implemented this interface would suddenly be missing an implementation. For example, if you had an interface (MyInterface) that was used by MyClass, then adding a method to MyInterface would break compatibility with MyClass.
In the best case scenario where you were responsible for the small number of classes that used MyInterface, this behaviour would be annoying but manageable—you’d just have to set aside some time to update your classes with the new implementation. However, things could become much more complicated if a large number of classes implemented MyInterface, or if the interface was used in classes that you weren’t responsible for.
While there were a number of workarounds for this problem, none of them were ideal. For example, you could include new methods in an abstract class, but this would still require everyone to update their code to extend this abstract class; and, while you could extend the original interface with a new interface, anyone who wanted to use these new methods would then need to rewrite all their existing interface references.
With the introduction of default methods in Java 8, it’s now possible to declare non-abstract methods (i.e. methods with a body) inside your interfaces, so you can finally create default implementations for your methods.
When you add a method to your interface as a default method, any class that implements this interface doesn’t necessarily need to provide its own implementation, which gives you a way of updating your interfaces without breaking compatibility. If you add a new method to an interface as a default method, then every class that uses this interface but doesn’t provide its own implementation will simply inherit the method’s default implementation. Since the class isn’t missing an implementation, it’ll continue to function as normal.
In fact, the introduction of default methods was the reason that Oracle was able to make such a large number of additions to the Collections API in Java 8.
Collection is a generic interface that’s used in many different classes, so adding new methods to this interface had the potential to break countless lines of code. Rather than adding new methods to the Collection interface and breaking every class that was derived from this interface, Oracle created the default method feature, and then added these new methods as default methods. If you take a look at the new Collection.Stream() method (which we’ll be exploring in detail in part three), you’ll see that it was added as a default method:
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
Creating a default method is simple—just add the default modifier to your method signature:
public interface MyInterface {
void interfaceMethod();
default void defaultMethod(){
Log.i(TAG,"This is a default method”);
}
}
Now, if MyClass uses MyInterface but doesn’t provide its own implementation of defaultMethod, it’ll just inherit the default implementation provided by MyInterface. For example, the following class will still compile:
public class MyClass extends AppCompatActivity implements MyInterface {
}
An implementing class can override the default implementation provided by the interface, so classes are still in complete control of their implementations.
While default methods are a welcome addition for API designers, they can occasionally cause a problem for developers who are trying to use multiple interfaces in the same class.
Imagine that in addition to MyInterface, you have the following:
public interface SecondInterface {
void interfaceMethod();
default void defaultMethod(){
Log.i(TAG,"This is also a default method”);
}
}
Both MyInterface and SecondInterface contain a default method with exactly the same signature (defaultMethod). Now imagine you try to use both of these interfaces in the same class:
public class MyClass extends AppCompatActivity implements MyInterface, SecondInterface {
}
At this point you have two conflicting implementations of defaultMethod, and the compiler has no idea which method it should use, so you’re going to encounter a compiler error.
One way to resolve this problem is to override the conflicting method with your own implementation:
public class MyClass extends AppCompatActivity implements MyInterface, SecondInterface {
public void defaultMethod(){
}
}
The other solution is to specify which version of defaultMethod you want to implement, using the following format:
<interface name>.super.<method name>();
So if you wanted to call the MyInterface#defaultMethod() implementation, then you’d use the following:
public class MyClass extends AppCompatActivity implements MyInterface, SecondInterface {
public void defaultMethod(){
MyInterface.super.defaultMethod();
}
}
Similar to default methods, static interface methods give you a way of defining methods inside an interface. However, unlike default methods, an implementing class cannot override an interface’s static methods.
If you have static methods that are specific to an interface, then Java 8’s static interface methods give you a way of placing these methods inside the corresponding interface, rather than having to store them in a separate class.
You create a static method by placing the keyword static at the beginning of the method signature, for example:
public interface MyInterface {
static void staticMethod(){
System.out.println("This is a static method");
}
}
When you implement an interface that contains a static interface method, that static method is still part of the interface and isn’t inherited by the class implementing it, so you’ll need to prefix the method with the interface name, for example:
public class MyClass extends AppCompatActivity implements MyInterface {
public static void main(String[] args) {
MyInterface.staticMethod();
...
...
...
This also means that a class and an interface can have a static method with the same signature. For example, using MyClass.staticMethod and MyInterface.staticMethod in the same class won’t cause a compile-time error.
The addition of static interface methods and default methods has led some developers to question whether Java interfaces are becoming more like abstract classes. However, even with the addition of default and static interface methods, there are still some notable differences between interfaces and abstract classes:
Traditionally, one of the limitations of Java annotations has been that you cannot apply the same annotation more than once in the same location. Try to use the same annotation multiple times, and you’re going to encounter a compile-time error.
However, with the introduction of Java 8’s repeating annotations, you’re now free to use the same annotation as many times as you want in the same location.
In order to ensure your code remains compatible with earlier versions of Java, you’ll need to store your repeating annotations in a container annotation.
You can tell the compiler to generate this container, by completing the following steps:
@Repeatable meta-annotation (an annotation that’s used to annotate an annotation). For example, if you wanted to make the @ToDo annotation repeatable, you’d use: @Repeatable(ToDos.class). The value in parentheses is the type of container annotation that the compiler will eventually generate.
public @interface ToDos {
ToDo[] value();
}
Attempting to apply the same annotation multiple times without first declaring that it’s repeatable will result in an error at compile-time. However, once you’ve specified that this is a repeatable annotation, you can use this annotation multiple times in any location where you’d use a standard annotation.
In this second part of our series on Java 8, we saw how you can cut even more boilerplate code from your Android projects by combining lambda expressions with method references, and how to enhance your interfaces with default and static methods.
In the third and final installment, we’ll be looking at a new Java 8 API that lets you process huge amounts of data in a more efficient, declarative manner, without having to worry about concurrency and thread management. We’ll also be tying together a few of the different features we’ve discussed throughout this series, by exploring the role that Functional Interfaces have to play in lambda expressions, static interface methods, default methods, and more.
And finally, even though we’re still waiting for Java 8’s new Date and Time API to officially arrive on Android, I’ll show how you can start using this new API in your Android projects today, with the help of some third-party libraries.
In the meantime, check out some of our other posts on Java and Android app development!