JAVA : How get to the List<String> - java

I create class Book with few values.
private int id;
private String title;
private String autorName;
private String autorSurname;
private int date;
private List<String> typeBook = Arrays.asList("autobiography", "classic", "comedy", "cookbook",
"crime story", "drama", "encyclopedia", "fantasty", "novel");
create a class constructor
public Book(int id, String t, String aName, String aSurname, int d, List<String> tBook)
{
this.id = id;
this.title = t;
this.autorName = aName;
this.autorSurname = aSurname;
this.date = d;
this.typeBook = tBook;
}
I want in Main create Object Book
Book b = new Book(1, "test", "xxx", "yyy", 2018, tBook);
And I have a question. How to get to the list,then choose the type of book ??

It seems that you are using the wrong structure for typeBook. A book can't be both an encyclopedia and a novel. It's just one type, selected from a set of choices. What you need is an enum:
enum BookType { ENCYCLOPEDIA, NOVEL, AUTOBIOGRAPHY, etc... };
class Book {
...
private BookType bookType;
public Book(int id, String t, String aName, String aSurname, int d, BookType bookType) {
...
}
}
Following DaveyDaveDave's and Jack Flump's helpful comments, you might want to put a book into a number of categories. For that, you can store an EnumSet in the Book class:
class Book {
...
private EnumSet<BookType> bookTypes;
...
}
And to make it easy to use, you can make the constructor take a variable argument list:
public Book(int id, String t, String aName, String aSurname, int d, BookType... bookTypes) {
...
this.bookTypes = EnumSet.of(bookTypes);
}
And call it like this:
Book tlotr = new Book(
12345,
"The Lord of the Rings",
"J.R.R.", "Tolkien",
1954,
BookType.CLASSIC, BookType.FANTASY, BookType.NOVEL);
If you want to avoid typing BookType. many times, you can add a static import statement at the top of your file:
import static my_package.BookType.*;
Then you can refer to the enum constants just by name. This only works if your source is in a named package. Also, if the enum is inside a class (such as book) then import static mypackage.Book.BookType.*;

I would look at DodgyCodeException's answer setting up a BookType enum. I'm also going to make the assumption that you're trying to get a List of Books by Type, since it's not entirely clear what you mean by the question.
If you're trying to get a List of Books, you're going to want to implement a MultiValueMap. Just for the sake of example:
Map<BookType, List<Book>> books = new HashMap<>();
books.computeIfAbsent(BookType.ENCYCLOPEDIA, () -> new ArrayList<Book>()).add(new Book(...));
Once you populate this datastructure. You can get all the books of a certain type.
List<Book> encyclopedias = books.get(BookType.ENCYCLOPEDIA);

Create getter for typeBook: List<String> getTypeBook() {return typeBook;}. Then use it: ...book.getTypeBook().get(index);

private List<String> typeBook = Arrays.asList("autobiography", "classic", "comedy", "cookbook", "crime story", "drama", "encyclopedia", "fantasty", "novel");
public void setTypeBook(List<String> typeBook){
this.typeBook = typeBook;
}
public List<String> getTypeBook(){
return this.typeBook;
}
public Book(int id, String t, String aName, String aSurname, int d, List<String> tBook){
this.id = id;
this.title = t;
this.autorName = aName;
this.autorSurname = aSurname;
this.date = d;
this.typeBook.addAll(tBook);
}

Related

search an array in java and print the output

In this java program I am trying to search if an ISBN number exists in the "Book" type array or not. But when I try to implement the method and display the output, I am getting an error which says " The method searchBook(Book, String) is undefined for the type Book". The <-- HERE comment shows where the error pops up. I do not understand how to rectify this error and any help will be appreciated. Thank you.
The driver class is : QuizMain
public class User {
int ID;
String name;
String email;
int age;
String isbn;
void searchBook(Book[] b, String isbn) {
for (int i =0;i<6;i++) {
if (b[i].ISBN == isbn) {
System.out.println(b[i].title);
} else {
System.out.println("ISBN Not Found");
}
}
}
}
public class Book {
String title;
String author;
String ISBN;
float rating;
int noOfDays;
void displayBookDetails() {
System.out.println("Title\tAuthor\tISBN\tRating"+this.title +this.author + this.ISBN +this.rating);
}
// book constructor
public Book(String title, String author, String ISBN, float rating) {
this.title = title;
this.author = author;
this.ISBN = ISBN;
this.rating = rating;
}
}
public class QuizMain {
public static void main(String[] args) {
Book[] arr = new Book[6];
arr[0] = new Book("Vincent la la ","king","2194-5357",6.5f);
arr[1] = new Book("A man of wisdom","henry","2193-4567",3.2f);
arr[2] = new Book("Apple Garden","timorthy","2104-3080",1.2f);
arr[3] = new Book("Sherlock","Arthur","2165-0932",5.5f);
arr[4] = new Book("Hello John","Tarnia","2134-2342",1.5f);
arr[5] = new Book("Tarzan","Martin","2111-0564",4.2f);
for(int i =0;i<arr.length;i++) {
arr[i].searchBook(arr[i], "2165-0932"); // <-- HERE
}
arr.searchBook(arr[5], "2165-0932"); // <-- HERE
}
}
In the User class the searchBook(Book[] b, String isbn) method accepts an array of Book and a String isbn value.
But while calling this method you are passing only one Book object instead of array of Book.
Move the searchBook implementation to QuizMain class and call this by passing array of Book as shown below for a workaround .
searchBook(arr, "2165-0932");
May be you need to concentrate on designing the class and its behavior.
There are two problems in your code. First one your searchBook function expecting Book type array and string but you are passing it one Book instant i.e arr[i] with string and secondly you have define the searchBook() function in User class and using it with object of Book class. Move your function to Book class. Even you don't need that function in any of Book or User class you can simply define static function searchBook(Book[] books, String isbn) inside your QuizMain class and call it like
searchBook(arr,"8344-3452")

Add episode to tvseries

So I am a student who just started with java and got this task.
''Make a class which represent an episode in a TVSeries. This should contain instance variables for episode, season, title and playtime. We would also make to constuctors to be able to create an episode, one with all the instance variables, and one without playtime (overloading).
Then make a class which represent a TVSeries. This should contain instance variables for title, description, release date and a list with episodes.
An episode shall be able to individually added via a methode addEpisodes(Episode theEpisode)''
So I have made the two classes (Episode with two constructors and TVSeries), but don't know what the addEpisodes(Episode theEpisode) methode shall contain. Would appreciate some help :)
public class TVSerie {
private String titel;
private String description;
private LocalDate releaseDate;
private ArrayList<Episode> listeWithEpisods;
public void addEpisode(Episode theEpisode) {
ArrayList<Episode> listeWithEpisods = new ArrayList<>();
listeWithEpisods.add(theEpisode);
System.out.println(listeWithEpisods);
}
public class Episode extends TVSerie {
private int episodeNumber;
private int sesongNumber;
private String titel;
private int playtime;
public Episode(int episodeNumber, int sesongNumber, String titel, int playtime) {
this.episodeNumber = episodeNumber;
this.sesongNumber = sesongNumber;
this.titel = titel;
this.playtime = spilletid;
}
public Episode(int episodeNummer, int sesongNummer, String tittel) {
this.episodeNumber = episodeNumber;
this.sesongNumber = sesongNumber;
this.titel = titel;
}
As the assignment suggest, TVSeries should have List and addEpisode needs to add it to your list.
public class TVSerie {
private String titel;
private String description;
private LocalDate releaseDate;
private List<Episode> listeWithEpisods;
public TVSerie(){
listeWithEpisods = new ArrayList<>();
}
public void addEpisode(Episode theEpisode) {
listeWithEpisods.add(theEpisode);
System.out.println(listeWithEpisods);
}
You need to initialize your list only once, inside the constructor.
In your implementation every time addEpisode is used you create new instance of your episode list and therefore deletes the former one.
In addition, Episode should not extends TVSerie, it is not a type of it. It is a type of it's own not related to TVSerie.

How to save a class instance in an ArrayList that is in the class? It has to be done in the constructor (Java)

Given a class like the this:
public class Book {
private String title;
private int pages;
private static ArrayList<Book> ArrayBooks = new ArrayList<Book>();
public Book(String titl, int page){
title=titl;
pages=page;
}
}
How can I keep a reference to every Book in the List, in a way that doesn't require any special calls - ie done automatically by the constructor.
Also, the List should have a max size of 20 books; if the user attempts to create the 21st book, he shouldn't be able to.
Can anyone figure out a way to implement it?
To access the current object, you could use the this reference. So your constructor could look like this:
public Book(String title, int pages) {
this.title = title; // avoid abbreviations like "titl"
this.pages = pages; // or "page" just to avoid same variable names
ArrayBooks.add(this); // add new Book instance into the list
}
To avoid more than 20 entries, you have to check the current amount of entries in the list:
public Book(String title, int pages) {
this.title = title;
this.pages = pages;
(if ArrayBooks.size < 20) {
ArrayBooks.add(this); // add new Book instance into the list
}
}
And I recommend to read the Java naming conventions. So ArrayBooks should be arrayBooks.
Edit
To prohibit more than 20 Book instances, you'll need a factory method that takes care about creating the instances for you:
public static Book create(final String title, final int pages) {
if (ArrayBooks.size() < 20) {
final Book instance = new Book(title, pages);
ArrayBooks.add(instance);
return instance;
}
return null;
}
private Book(String title, int pages) { // "hide" the constructor, so the user can't use this instead of the factory
this.title = title;
this.pages = pages;
}
You could also throw an exception in your constructor, but I personally don't like that. It is up to you, which way you take.
Add this to the List, and throw an exception if the user attempts to create the 21st:
public class Book {
private static final List<Book> books = Collections.synchronizedList(new ArrayList<Book>());
private String title;
private int pages;
public Book(String title, int pages) {
if (books.size() == 20)
throw new IllegalStateException("Maximum number of books reached");
this.title = title;
this.pages = pages;
books.add(this);
}
}
I've added a call to Collections.synchronizedList() to add simple thread safety to prevent the maximum from being exceeded due to race conditions.
Also note the change of the list type to List<Book> (from ArrayList<Book>) - see Liskov substitution principle
I recommend to use list because it's good in some parameter then array.
public Book (String titl, int page) {
title = titl;
pages = page;
Arraylist.add(this); // add new Book in the list
}
For not giving more then 20
public Book (String titl, int page) {
title = titl;
pages = page;
if (Arraylist.size() < 20) {
Arraylist.add(this); // add new Book into the list
}
}
Try to apply first your own logic.

Storing an object within an object

Since my post yesterday regarding constructing a link list from scratch I have made some progress.
I have encountered a new hurdle: storing an object within an object.
Lets say I have a 'book' class with the following attributes (forgetting all the set & get methods which I am familiar with):
private String title;
private int rating;
How would I then reference another class such as 'author' as obviously a book must have an author and many books may have the same or more then one author.
Here is my 'author' class attributes (again ignoring gets & sets):
String authorName;
String authorEmail;
Am I right in thinking I need to initiate an object of 'author' within the 'book' class as such:
private String title;
private int rating; //mine
private Author author = new Author();
Would I then have to set the attributes authorName and authorEmail everytime I made a new instance of 'book'?
Many thanks in advance for constructive feedback.
You don't necessarily need to instantiate the Author object right there where you declare the attribute. I would suggest something like passing in an already-instantiated Author either to the constructor of the Book class or to a setter. Then you could pass the same Author in to each Book you create that should be associated with it.
EDIT: added some code snippets:
For instance, if you made your Book constructor something like this:
public Book(String title, int rating, Author author) {
// set this.title, this.rating, and this.author to the passed-in parameters...
}
Then you would invoke it in code like this:
Author bob = new Author();
// You can set the name and email of the Author here using setters,
// or add them as args in the Author constructor
Book firstBook = new Book("The First Book", 1, bob);
Book secondBook = new Book("The Second Book", 2, bob);
This is a many to many relationship. You need your Author class to simply be a link between a person and a book. Then things will work out.
You might want some kind of singleton author list in order to prevent many copies of the same author. Either that, or you will definitely need to override the equals method of author.
If you use a singleton, you could have a getAuthor routine in your AuthorList object that either makes an author if it doesn't exist or fetches the already created author.
Your on the right track. You can use an ArrayList to be able to dynamically add new authors without having to resize anything. Let me clarify it for you:
class Book {
private String title;
private int rating;
private List<Author>authors = new ArrayList<Author>();
public Book(String title, int rating, Author author) {
this.title = title;
this.rating = rating;
authors.add(author);
}
public Book(String title, int rating, Author author) {
this.title = title;
this.rating = rating;
this.author = author;
}
public void addAuthor(Author a) {
authors.add(a);
}
public int numberOfAuthors() {return authors.size();}
}
class Author {
private String name;
private String email;
public Author(String name, String email) {
//...Same thing
}
}
class Main {
public static void main(String[] args) {
Book book = new Book("Java Programming", 5, new Author("Me", "me#gmail.com"));
Author contributingAuthor = new Author("My Friend", "cupcakes#gmail.com");
book.addAuthor(contributingAuthor);
}
}

Questions about enum

If I have a Object
public class Genre {
private int id;
private int name;
}
And the id and name were been determined in advance, for example
if (id == 1)
name = "action";
else if (id == 2)
name = "horror";
My problem is how to create these two methods well
Genre.getName(1); // return "action";
Genre.getId("action"); // return 1;
I thought maybe I can use enum, like
public enum Genre {
ACTION(1), HORROR(2);
private final int id;
private final String name;
private Genre(int id) {
this.id = id;
this.name = getName(id);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static String getName(int i) {
switch(i) {
case 1 : return "action";
case 2: return "horror";
default :
return null;
}
}
}
But in this way, I have no idea how to
Genre.getId("action"); // return 1;
And im afraid i use enum not correctly.
Could you give me some advice? Thanks!
---
At first, What I want to do this is in my case i want to use id or name to find the name or id like
int id = 1;
Genre.getName(id); // return "action"
or
String name = "action";
Genre.getId(name); // return 1
And now thanks for all the advices, I realize why I want to do is
int id = 1;
Genre.getGenre(id); // return Genre that id = 1 and the name = "action"
or
String name = "action";
Genre.getGenre(name); // return Genre that id = 1 and the name = "action"
If you insist on using an enum for this, you can just use the existing enum facilities. The solution below assumes the enum name and ordinal may be used in place of your name and id fields:
public enum Genre {
// ordinal 0, name = "ACTION"
ACTION,
// ordinal 1, name = "HORROR"
HORROR;
}
public static void main(String[] args) {
int horrorOrdinal = 1;
Genre horrorGenre = Genre.values()[horrorOrdinal];
String horrorName = horrorGenre.name();
String actionName = "ACTION";
Genre actionGenre = Genre.valueOf(actionName);
int actionOrdinal = actionGenre.ordinal();
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
Output:
HORROR=1 ACTION=0
Another suitable way would be to use a map for the lookup, like Michał Šrajer suggested:
private static Map<Integer, String> genres = new HashMap<Integer, String>();
public static void main(String[] args) {
initGenres();
int horrorOrdinal = 2;
String horrorName = genres.get(horrorOrdinal);
String actionName = "action";
int actionOrdinal = getGenreIdByName(actionName);
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
private static void initGenres() {
genres.put(1, "action");
genres.put(2, "horror");
}
private static int getGenreIdByName(String genreName) {
for (Entry<Integer, String> entry : genres.entrySet()) {
if (entry.getValue().equals(genreName)) {
return entry.getKey();
}
}
throw new IllegalArgumentException("Genre not found: " + genreName);
}
Output:
horror=2 action=1
Design considerations:
In this example I chose to use the (fast) map lookup for id->name and wrote a seperate method (getGenreIdByName) to do the reverse lookup name->id. You could reverse that, or use a second map to make both lookups fast (at the cost of needing to maintain an extra map).
I chose to store the id and name in the map. You could also use the Genre class itself as the map value. This would allow you to easily add extra fields (like 'description') later on.
If you need to represent you genres in different languages, you can use ResourceBundles to localize the output. Create a language file in your classpath root.
In file genres_nl.properties:
horror=heel eng
action=actie
Where the _nl suffix in the filename indicates the language.
Then in your code, in initGenres:
ResourceBundle genreNames = ResourceBundle.getBundle("genres", new Locale("nl");
And when getting the genre name:
String horrorName = genreNames.getString(genres.get(horrorOrdinal));
Note that getString can throw the runtime exception MissingResourceException if the bundle is not found. To avoid this, make sure you create a 'default' bundle with no suffix (so in this case a file named 'genres.properties') which is automatically used in case no bundle for the used Locale can be found.
Try the valueOf(...) method:
void String getId(String name) {
//names are upper case, so account for that
//handling non-existent names is an excersize for you
valueOf(name.toUpperCase()).getId();
}
Note that there are better methods (like Thilo suggested), but if you have a string only, you might use that.
Edit: another note:
In your getName(int i) method, you might want to return ACTION.name() etc. in order to be more refactoring safe and use the correct case.
You can get its ID by calling Genre.ACTION.getId();
This should do it:
Genre.ACTION.getId()
And if you need to do it at run-time:
Genre.valueOf("ACTION").getId()
ACTION(1, "action"), HORROR(2, "horror");
is a easy way to do it.
But if you are require to do it more often i would suggest you to create your own class and use MAP<-"-,-"-> as micheal said.
Edit:----
As you said the rarely gonna change use this way-->
public enum Genre {
ACTION(0, "action"), HORROR(1, "horror"), ROMANCE(2, "romance"), COMEDY(5, "comedy");
public final int id;
public final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
};
public final static int length = Genre.values().length;
public static String[] getGenre() {
String[] genreList = new String[length];
int i = 0;
for (Genre attribute : Genre.values()) {
genreList[i++] = attribute.toString();
}
return genreList;
}
#Override
public String toString() {
return this.name;
}
}
Please remember use this as Genre.HORROR.id
also note that using this way is best as per your requirement.
Why don't you use the Enum Constructor with id and String:
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
}
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
private final int id;
private final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
If you need to access particular element by it's name, you need to do it this way:
Genre.valueOf("ACTION").getId()
However, if you need to do it often, and in more dynamic way, I suggest to create regular class, and to keep all data in some Map<String, Movie> container.

Categories

Resources