---
title: Introduction of Interface in Spring Boot and Java8
description:
---
# Introduction of Interface in Spring Boot and Java8
###### Author: TYT
###### Tags: `Reading notes`, `Java`, `Spring Boot`,`Interface`
- [Introduction](#Introduction)
- What, why, when, and how
- [Usage](#Usage)
- Single and muliple implement (inter-, intra, and unit test)
- [Misuse and overuse](#Misuse-and-overuse)
- [Summary](#Summary)
- [Quiz](#Quiz)
---
## Introduction
### What is interface?
- Interface is a reference type.
- Contain method signature, default method, and static method.
- Cannot be instantiated, only be implemented by class and extended by interface.
```java
public interface RoadVehicle {
String drive(String direction);
// can be used when class implemented.
default void turnoff() {
System.out.println("turn off");
}
// can be used without implementaton.
static void honk() {
System.out.println("Do Do!");
}
}
```
### Why use interface?
- Achieve
- Loose coupling
:::spoiler Tight coupling vs. Loose coupling
- Tight coupling
```java
public class Person {
public static void main(String[] args){
Shopping shopping = new Shopping();
shopping.pay();
}
}
```
We have to commit and uncommit for switching payment instrument to pay.
Otherwise, creat more shopping class, Shopping1 and Shopping2, etc. to cater to payment instrument instead of commit and uncommit.
```java
public class Shopping {
public void pay(){
CreditCard creditCard = new CreditCard();
creditCard.pay();
// SmartPhone smartPhone = new SmartPhone();
// smartPhone.pay();
}
}
```
```java
public class CreditCard {
public void pay(){
System.out.println("Pay by credit card.");
}
}
```
```java
public class SmartPhone {
public void pay(){
System.out.println("Pay by smart phone.");
}
}
```
- Loose coupling
Person can controll the payment instrument he/she want, kind of IoC I think.
```java
public class Person {
public static void main(String[] args){
PaymentInstrument creditCard = new CreditCard();
// PaymentInstrument smartPhone = new SmartPhone();
Shopping shopping = new Shopping(creditCard);
shopping.pay();
}
}
```
Creat variable to switch payment instrument easier.
```java
public class Shopping {
private PaymentInstrument paymentInstrument;
public Shopping(PaymentInstrument paymentInstrument){
this.paymentInstrument = paymentInstrument;
}
public void pay() {
paymentInstrument.pay();
}
}
```
```java
public interface PaymentInstrument {
void pay();
}
```
```java
public class CreditCard implements PaymentInstrument{
@Override
public void pay(){
System.out.println("Pay by credit card.");
}
}
```
```java
public class SmartPhone implements PaymentInstrument{
@Override
public void pay(){
System.out.println("Pay by smart phone.");
}
}
```
:::
::: spoiler Recommended vedio
{%youtube ifufbHjIQCo %}
:::
- Multiple implement and interitance
- Switch implement easily
### When use interface
- Specify the "behavior" of a particular data type
- Expect the unrelated class whould implenment the interface
- Storage device (interface) - Optical disc (1965), Floppy disk drive (1971), and USB flash drive (2000), etc.(class)
- Multiple implement and interface
- Class USB flash drive implenments interface storage device and charging equipment.
### How to use interface?
- Interface
:::spoiler Use "extends" to extend the interface.
``` java
public interface I002 extends I001 {
//TODO
}
```
:::
:::spoiler Use "," when mutiple interface is extended.
``` java
public interface I003 extends I001, I002 {
//TODO
}
```
:::
- Class
:::spoiler Use "implenments" to implenments the interface
``` java
public class C001 implenments I001 {
//TODO
}
```
:::
:::spoiler Use "," when mutiple interface is implenmented.
``` java
public interface C002 implenments I001, I002 {
//TODO
}
```
:::
:::spoiler Should create all method body which method signature is declared in interface.
``` java
public interface I001 {
String greeting ();
}
```
```java
public class C001 implenments I001 {
publc greeting (){
return "hello";
}
}
```
:::
## Usage
### One implement
:::spoiler Instantiate implement in native Java, likes ```List<int> list = new ArrayList<>()```, ```Map<String, Object> map = new HasMap<>()```, etc.
```java
@RestController
@RequestMapping("/One")
public class PersonA1Controller {
@RequestMapping(value = "/PersonA1", method = RequestMethod.GET)
public String PersonA1(){
PaymentInstrumentA paymentInstrumentA = new CreditCardA();
return paymentInstrumentA.pay(); // Pay by credit card A.
}
}
```
``` java
public interface PaymentInstrumentA {
String pay ();
}
```
```java
@Service
public class CreditCardA implements PaymentInstrumentA {
@Override
public String pay(){
return "Pay by credit card A.";
}
}
```
:::
:::spoiler Use @Service/ @Component in Spring Boot
```java
@RestController
@RequestMapping("/One")
public class PersonA2Controller {
@Autowired
PaymentInstrumentA paymentInstrumentA;
@RequestMapping(value = "/PersonA2", method = RequestMethod.GET)
public String PersonA2(){
return paymentInstrumentA.pay();
}
}
```
``` java
public interface PaymentInstrumentA {
String pay ();
}
```
```java
@Service
public class CreditCardA implements PaymentInstrumentA {
@Override
public String pay(){
return "Pay by credit card A.";
}
}
```
:::
### Multiple implement
- Inter-class
:::spoiler Use default name (lowercase in the first letter) as variable name.
```java
@RestController
@RequestMapping("/Multiple/Inter")
public class PersonB1Controller {
@Autowired
PaymentInstrumentB creditCardB1ServiceImpl;
@RequestMapping(value = "/PersonB1", method = RequestMethod.GET)
public String PersonB1(){
return creditCardB1ServiceImpl.pay(); // Pay by credit card B1.
}
}
```
```java
public interface PaymentInstrumentB {
String pay();
}
```
``` java
@Service
public class CreditCardB1ServiceImpl implements PaymentInstrumentB {
@Override
public String pay() {
return "Pay by credit card B1.";
}
}
```
:::
:::spoiler Name implenment and use @Qualifier to specify default implenment
```java
@RestController
@RequestMapping("/Multiple/Inter")
public class PersonB2Controller {
@Qualifier("CreditCardB2ServiceImpl")
@Autowired
PaymentInstrumentB paymentInstrumentB;
@RequestMapping(value = "/PersonB2", method = RequestMethod.GET)
public String pay(){
return paymentInstrumentB.pay(); // Pay by credit card B2.
}
}
```
```java
public interface PaymentInstrumentB {
String pay();
}
```
``` java
@Service("CreditCardB2ServiceImpl")
public class CreditCardB2ServiceImpl implements PaymentInstrumentB {
@Override
public String pay() {
return "Pay by credit card B2.";
}
}
```
:::
:::spoiler Use @Primary to specify default implenment
```java
@RestController
@RequestMapping("/Multiple/Inter")
public class PersonB3Controller {
@Autowired
PaymentInstrumentB creditCardCService;
@RequestMapping(value = "/PersonB3", method = RequestMethod.GET)
public String pay(){
return creditCardCService.pay(); // Pay by credit card B3.
}
}
```
```java
public interface PaymentInstrumentB {
String pay();
}
```
``` java
@Primary
@Service
public class CreditCardB3ServiceImpl implements PaymentInstrumentB {
@Override
public String pay() {
return "Pay by credit card B3.";
}
}
```
:::
- Intra-class
:::spoiler Instantiate implenment to switch
```java
@RestController
@RequestMapping("/Multiple/Intra")
public class PersonCController {
@Qualifier("CreditCardC1")
@Autowired
PaymentInstrumentC paymentInstrumentC;
@RequestMapping(value = "/PersonC1", method = RequestMethod.GET)
public String payD001(){
return paymentInstrumentC.pay(); // Pay by credit card C1.
}
@RequestMapping(value = "/PersonC2", method = RequestMethod.GET)
public String payD002(){
PaymentInstrumentC paymentInstrumentC = new CreditCardC2();
return paymentInstrumentC.pay(); // Pay by credit card C2.
}
}
```
``` java
public interface PaymentInstrumentC {
String pay();
}
```
```java
//@Primary
@Service("CreditCardC1")
public class CreditCardC1 implements PaymentInstrumentC {
@Override
public String pay() {
return "Pay by credit card C1.";
}
}
```
```java
@Service("CreditCardC2")
public class CreditCardC2 implements PaymentInstrumentC {
@Override
public String pay() {
return "Pay by credit card C2.";
}
}
```
:::
- Will Run build failed if don't use @Primary, @Qualifer, and default name, e.g. [stackoverflow](https://stackoverflow.com/questions/46343560/class-required-a-single-bean-but-2-were-found).
```
Description:
Field {interfaceName} in {class which declars interface}required a single bean, but 2 were found:
{implenment01}: defined in fill {file path}
{implenment02}: defined in fill {file path}
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
```
- With unit test
- App code
- Use @Primary/ name implenment, and use @Qualifier/ default name to specify implenment.
```java
@RestController
@RequestMapping("Multiple/UnitTest")
public class PersonDController {
@Autowired
PaymentInstrumentD paymentInstrumentD;
@RequestMapping(value = "/PersonD", method = RequestMethod.GET)
public String pay(){
return paymentInstrumentD.pay(); // Pay by credit card D.
}
}
```
```java
public interface PaymentInstrumentD {
String pay();
}
```
```java
// @Primary
@Service
public class CreditCardD implements PaymentInstrumentD {
@Override
public String pay() {
return "Pay by credit card D.";
}
}
```
- Unit test code
:::spoiler use default name/ @Qualifier to specify implenment.
- default name
```java
@RunWith(SpringRunner.class)
@ContextConfiguration(classes=ShareApplication.class)
public class PersonDControllerTest1 {
@Autowired
PaymentInstrumentD creditCardDTest1;
@Test
public void pay(){
System.out.println(creditCardDTest1.pay());
}
}
```
```java
@Service
public class CreditCardDTest1 implements PaymentInstrumentD {
@Override
public String pay() {
return "Pay by credit card D Test 1.";
}
}
```
- @Qualifier
```java
@RunWith(SpringRunner.class)
@ContextConfiguration(classes=ShareApplication.class)
public class PersonDControllerTest2 {
@Qualifier("CreditCardDTest2")
@Autowired
PaymentInstrumentD paymentInstrumentD;
@Test
public void pay(){
System.out.println(paymentInstrumentD.pay());
}
}
```
```java
@Service("CreditCardDTest2")
public class CreditCardDTest2 implements PaymentInstrumentD {
@Override
public String pay() {
return "Pay by credit card D Test 2.";
}
}
```
:::
:::spoiler Will get return from app code if do not use default name/ @Qualifier to specify implenment.
```java
@RunWith(SpringRunner.class)
@ContextConfiguration(classes=ShareApplication.class)
public class PersonDControllerTest2 {
@Qualifier("CreditCardDTest2")
@Autowired
PaymentInstrumentD paymentInstrumentD;
@Test
public void pay(){
System.out.println(paymentInstrumentD.pay());
}
}
```
```java
@Service("CreditCardDTest2")
public class CreditCardDTest2 implements PaymentInstrumentD {
@Override
public String pay() {
return "Pay by credit card D Test 2.";
}
}
```
:::
- App code still get return from app code's implenment, even unit test use @Primary.
- Will Run build failed if don't use @Primary, @Qualifer, and default name.
```
Description:
Field {interfaceName} in {class which declars interface}required a single bean, but 2 were found:
{implenment01}: defined in fill {file path}
{implenment02}: defined in fill {file path}
Action:
Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
```
- If app code and unit test code both use @primary
- Run build will be succussed.
- Run test will be failed.
## Misuse and overuse
- Create interface just in case.
- Create interface is only for a class.
- Create all method body which declare in interface.
- Name implenment after interface.
- bad
``` java
public interface PaymentInstrument {
String pay();
}
```
```java
@Service
public class PaymentInstrumentImpl implenments PaymentInstrument {
publc pay(){
return "Pay by paymentInstrumentImpl!";
}
}
```
- better
``` java
public interface PaymentInstrument {
String pay();
}
```
```java
@Service
public class CreditCardVisa implenments PaymentInstrument {
publc pay(){
return "Pay by Visa!";
}
}
```
## Summary
- Interface characteristics
- Loose coupling.
- Multiple implenment and ingeritance.
- Switch implenment easily.
- Usage
- Create a interface to extend interface.
- Create a class to implenment interface.
- Use @Primary or name implenment, e.g. @Service("serviceName") and @Component("componentName")
- Use default name or @Qualifier to specify implenment when declare interface.
- Misuse and overuse
- Avoid using without planing.
- Create interface is only for a class.
## Quiz
- Output of following Code
(A) Hello!
(B) Hi!
```java
public class Main {
@Autowired
IService i002ServiceImpl;
publc static void main(String[] args){
iService.greeting();
}
}
```
``` java
public interface IService {
String greeting ();
}
```
```java
@Primary
@service("I001")
public class I001ServiceImpl extends Base {
publc void greeting(){
System.out.println("Hello!");
}
}
```
```java
@Service("I002")
public class I002ServiceImpl extends Base {
publc void greeting(){
System.out.println("Hi!");
}
}
```
:::spoiler Answer
(B) Hello!
:::