I don't know if this is possible in Java but I was wondering if it is possible to use an object in Java to return multiple values without using a class.
Normally when I want to do this in Java I would use the following
public class myScript {
public static void main(String[] args) {
// initialize object class
cl_Object lo_Object = new cl_Object(0, null);
// populate object with data
lo_Object = lo_Object.create(1, "test01");
System.out.println(lo_Object.cl_idno + " - " + lo_Object.cl_desc);
//
// code to utilize data here
//
// populate object with different data
lo_Object = lo_Object.create(2, "test02");
System.out.println(lo_Object.cl_idno + " - " + lo_Object.cl_desc);
//
// code to utilize data here
//
}
}
// the way I would like to use (even though it's terrible)
class cl_Object {
int cl_idno = 0;
String cl_desc = null;
String cl_var01 = null;
String cl_var02 = null;
public cl_Object(int lv_idno, String lv_desc) {
cl_idno = lv_idno;
cl_desc = lv_desc;
cl_var01 = "var 01";
cl_var02 = "var 02";
}
public cl_Object create(int lv_idno, String lv_desc) {
cl_Object lo_Object = new cl_Object(lv_idno, lv_desc);
return lo_Object;
}
}
// the way I don't really like using because they get terribly long
class Example {
int idno = 0;
String desc = null;
String var01 = null;
String var02 = null;
public void set(int idno, String desc) {
this.idno = idno;
this.desc = desc;
var01 = "var 01";
var02 = "var 02";
}
public int idno() {
return idno;
}
public String desc() {
return desc;
}
public String var01() {
return var01;
}
public String var02() {
return var02;
}
}
Which seems like a lot of work considering in Javascript (I know they are different) I can achieve the same effect just doing
var lo_Object = f_Object();
console.log(lo_Object["idno"] + " - " + lo_Object[desc]);
function f_Object() {
var lo_Object = {};
lo_Object = {};
lo_Object["idno"] = 1;
lo_Object["desc"] = "test01";
return lo_Object;
}
NOTE
I know the naming convention is wrong but it is intentional because I have an informix-4gl program that runs with this program so the coding standards are from the company I work for
The best way to do this is to use HashMap<String, Object>
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<String, Object> person =
new HashMap<String, Object>();
// add elements dynamically
person.put("name", "Lem");
person.put("age", 46);
person.put("gender", 'M');
// prints the name value
System.out.println(person.get("name"));
// asures that age element is of integer type before
// printing
System.out.println((int)person.get("age"));
// prints the gender value
System.out.println(person.get("gender"));
// prints the person object {gender=M, name=Lem, age=46}
System.out.println(person);
}
}
The advantage of doing this is that you can add elements as you go.
The downside of this is that you will lose type safety like in the case of the age. Making sure that age is always an integer has a cost. So to avoid this cost just use a class.
No, there is no such a feature, you have to type out the full type name(class name).
Or use may use val :
https://projectlombok.org/features/val.html
Also, if you use IntelliJ IDEA
try this plugin :
https://bitbucket.org/balpha/varsity/wiki/Home
I am not sure if it's possible with Java. Class is the primitive structure to generate Object. We need a Class to generate object. So, for the above code, i don't think there is a solution.
Java methods only allow one return value. If you want to return multiple objects/values consider returning one of the collections. Map, List, Queue, etc.
The one you choose will depend on your needs. For example, if you want to store your values as key-value pairs use a Map. If you just want to store values sequentially, use a list.
An example with a list:
list<Object> myList = new ArrayList<Object>();
myList.add("Some value");
return myList;
As a side note, your method create is redundant. You should use getters and setters to populate the object, or populate it through the constructor.
cl_Object lo_Object = new cl_Object(1, "test01");
The way you have it set up right now, you're creating one object to create another of the same type that has the values you want.
Your naming convention is also wrong. Please refer to Java standard naming convention:
http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-135099.html#367
Related
I'm trying to optimize a section of my code which requires an object array with constructor parameters in it. Is there a way to add that to the arguments of a method?
I have an array of objects called SongList in that array there are objects from the Song Class with constructor parameters:
songs[] songList = new songs[1];
songList[0] = new songs("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33);
I also have a method that searches the array based on the category and the search query:
//Method
public static songs[] search(songs SearchCategory , String Quarry){}
//Calling of method
search = AudioPlayer.search("aName", "Kenny Loggins");
Songs class:
public class songs {
String sName;
String fPath;
String aName;
double sLength;
public songs(String songName,
String filePath,
String Artist,
double songLength) {
sName = songName;
fPath = filePath;
aName = Artist;
sLength = songLength;
}
}
Is there a way I could make the first argument of the code accept a constructor parameter like Name? This would allow me to cut down the overall length of my code as I wouldn't need to use a switch statement.
Search method:
public static songs[] search(String SearchCategory , String Quarry){
//Returned array value
songs[] ReturnedResult = new songs[0];
// Method only list
List<songs> SearchResult = new ArrayList<songs>();
switch (SearchCategory) {
case "aName":
//for loop looks through all objects with the SearchCategory and places any found values into the list
for (songs songs : AudioListing) {
if (songs.aName.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "sName":
for (songs songs : AudioListing) {
if (songs.sName.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "fPath":
for (songs songs : AudioListing) {
if (songs.fPath.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "sLength":
//Since the given quarry is a string and the length is a double the quarry is converted
double QuarryDoubleTypeC = Double.parseDouble(Quarry);
for (songs songs : AudioListing) {
if (songs.sLength == QuarryDoubleTypeC) {
SearchResult.add(songs);
}
}
}
// Conversion of list to array for ease of use
ReturnedResult = SearchResult.toArray(ReturnedResult);
return ReturnedResult;
}
There is a concept of reflection in Java that you can use here.
You can use the SearchCategory to get the field value from the object
Then you can use it to compare with Quarry
The working code is as below
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Songs {
String sName;
String fPath;
String aName;
double sLength;
static Songs[] AudioListing = new Songs[1];
static {
AudioListing[0] = new Songs("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33);
}
public Songs(String songName, String filePath, String Artist, double songLength) {
sName = songName;
fPath = filePath;
aName = Artist;
sLength = songLength;
}
public static Songs[] search(String SearchCategory, String Quarry) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
// Returned array value
Songs[] ReturnedResult = new Songs[0];
// Method only list
List<Songs> SearchResult = new ArrayList<Songs>();
for (Songs song : AudioListing) {
Field field = Songs.class.getDeclaredField(SearchCategory);
String fieldValue = (String) field.get(song);
if (fieldValue.equals(Quarry)) {
SearchResult.add(song);
}
}
// Conversion of list to array for ease of use
ReturnedResult = SearchResult.toArray(ReturnedResult);
return ReturnedResult;
}
#Override
public String toString() {
return "Songs [sName=" + sName + ", fPath=" + fPath + ", aName=" + aName + ", sLength=" + sLength + "]";
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
//Calling of method
Songs[] results = Songs.search("aName", "Kenny Loggins");
System.out.println(Arrays.toString(results));
}
}
This explains how it can be achieved you can further enhance your code after further exploring in this direction.
This is an excellent opportunity to leverage higher-order functions.
In Java, these are realized via Functional Interfaces.
You can reference the methods -- or fields -- from your Song class (which should be capitalized and singular, not songs) itself via Songs::aName. Furthermore, if you are trying to find a value, leveraging Predicate<Song> is an excellent idea.
Also, using Collections instead of arrays is advisable.
In short, your code could easily look like this:
class AudioPlayer {
List<Song> audioListings = new ArrayList<>();
public void add(Song song) { audioListings.add(song); }
public List<Song> search(Predicate<Song> predicate) {
return audioListings.stream()
.find(predicate)
.collect(Collectors.toList());
}
}
You would then use it like this:
AudioPlayer player = new AudioPlayer();
// fill with songs
player.add(new Song("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33));
// find song with a specific aName
var songs = player.search(song => song.aName.equals("Kenny Loggins"));
The added benefit is that you can search for very complex things by constructing more complex predicates:
// find song with specific aName AND shorter then a given length
Predicate<Song> query =
song => song.aName.equals("Kenny Loggins")
.and(song => song.sLength <= 3.5);
var songs = player.search(query);
I would advise against using reflection for this. Reflection comes with a whole range of problems and it simply isn't needed. The approach I have outlined above is far more idiomatic Java since Java 8, scales better, is easier to read, less error-prone and overall cleaner.
What you're looking for is a bit advanced; it's the interface Function<Song, String>. This will allow you to provide some transformation that selects a string value for your Song object, particularly in this case such options as Song::getSName. This is how it would be done with streams (and collections):
songList.stream()
.filter(song -> quarry.equals(function.apply(song)))
.findAll();
However, I strongly recommend that you become more familiar with the basics of Java before diving into more complicated logic, especially standards about naming (classes should be capitalized; variables should not), collections (lists are usually preferred over arrays), static vs. instance members, and interfaces.
I created a list and a model with custom objects. I want to retreive the objects that are in the list, however, I get an error message, that String can not be converted to Object.
String cannot be converted to ARMAJTermek
Swing automatically creates the JList, to which then I add a new model.
DefaultListModel model = new DefaultListModel<ARMAJTermek>();
TermekList.setModel(model);
I need this, because I'm using a custom object, that has properties and methods, which I need to invoke later. For this, I overrode the .toString method, like this:
#Override
public String toString () {
String toString = "";
toString = this.nev+"\n"+this.cikkszam+"\n"+Integer.toString(this.bruttoKisker)+" Ft";
return toString;
}
This way, when I add an object to the JList, it appears as designed by the cell renderer (which is also unique, in a way that it displays JTextArea as a list element...).
for (int i... and lots of other code) {
model.addElement(termek[i]);
}
TermekList.setModel(model);
TermekList.revalidate();
TermekList.repaint();
After adding objects to the list, it appears correctly, runs correctly, as when I select an object in the lists, it's methods run correctly. However, when I try to make a copy of the selected object for a different JList, I'm unable to retrieve them. I tried getting it from the list itself with
ARMAJTermek termek = (ARMAJTermek)TermekList.getSelectedValue();
ARMAJTermek termek = (ARMAJTermek)TermekList.getModel().getElementAt(TermekList.getSelectedIndex());
(Different functions, that's why some variables have the same name even being different types.)
But I get the message, that these Strings can not be converted to ARMAJTermek. But I don't need the String representation of the objects, I need the objects themselves. I mean, if it's methods can be run by clicking on their String representation in the list, I should be able to make a copy of them, right?
public class ARMAJTermek {
String nev;
String cikkszam;
int bruttoKisker;
public ARMAJTermek(String nev, String cikkszam, int bruttoKisker) {
this.nev = nev;
this.cikkszam = cikkszam;
this.bruttoKisker = bruttoKisker;
}
#Override
public String toString () {
String toString = "";
toString = this.nev+"\n"+this.cikkszam+"\n"+Integer.toString(this.bruttoKisker)+" Ft";
return toString;
}
}
public ui_main() throws {
initComponents();
DefaultListModel model = new DefaultListModel<ARMAJTermek>();
TermekList.setModel(model);
ARMAJTermek termek[2];
termek[0] = new ARMAJTermek("lorem", "ipsum", 1);
termek[1] = new ARMAJTermek("lorem2", "ipsum2", 2);
}
public void addTermek(JList TermekList) {
DefaultListModel model = new DefaultListModel<ARMAJTermek>();
model.clear();
if(TermekList.getSelectedIndex() == 0){
TermekList.setSelectedIndex(1);
}
TermekList.removeAll();
for ( int i = 0; i < termek.length; i++ ) {
model.addElement(termek[i]);
}
TermekList.setModel(model);
TermekList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
TermekList.revalidate();
TermekList.repaint();
}
public void getTermek(JList TermekList) {
ARMAJTermek termek = (ARMAJTermek)TermekList.getSelectedValue();
ARMAJTermek termek = (ARMAJTermek)TermekList.getModel().getElementAt(TermekList.getSelectedIndex());
}
I made it run by creating a new function inside the function, that can take and store the ARMAJTermek object:
ARMAJTermek termek = ARMAStaticFunctions.getTermek(TermekList);
public static ARMAJTermek getTermek(JList TermekList) {
ARMAJTermek termek = (ARMAJTermek)TermekList.getSelectedValue();
return termek;
}
And now it works as intended, not trying to convert objects to String.
I have this class that serves as a container which I will use the instance variable for processing later
class Data{
static int counter= 0;
boolean boolean1;
String string1;
public Data() {
counter++;
}
}
And I have this method that sets the values of Data
public Data setData()
{
Data data = null;
for (int i = 0; i < somecoutnerhere; i++) {
Data = new Data();
Data.boolean1 = some boolean put here;
Data.string1 = "some string to be put here";
}
return ProcessData(Data);
}
I also have this class ProcessData that will make use of Data and will construct the response
private class ProcessData
{
private final Map<String, List<?>> map = new HashMap<String, List<?>>();
int counter;
public ProcessData(Data data)
{
map.put("boolean1", data.boolean1);
map.put("String1", data.string1);
counter = data.counter;
}
public String someMethodToGenerateReturnData(){
// some code here to make use of the Data collected. Will basically use map to construct the return String
}
}
My problem is that I couldn't figure out how can I return all the instance variables created on the for-loop for Data on setData(). Any thoughts?
My problem is that I couldn't figure out how can I return all the instance variables created on the for-loop for Data on setData(). Any thoughts?
According to this your problem is not "returning all instance one variables in one call", as your title states, but rather a question about how returning all Data-Objects created in your for-loop, which is easier.
Your code is erronous though, so I went ahead & corrected it (I hope I didn't mess up). I also renamed a few things.
The changes I made are:
renamed "boolean1" and "string1" to "trueOrFalse" and "string"
added a public, fully parameterized constructor to the Data-class
added a ProcessData-list to the setData()-method, which is filled in the for-loop
(+ a comment)
However, I'd strongly recommend you to check your architecture, and also to learn a bit about naming conventions, or coding conventions in general. Names should point out the purpose or content of the method/variable/class, and "boolean1" isn't really doing that.
Regarding the architecture: The Data-class seems to exist solely for the counter, and you could easily change that, making the Data-class obsolete (unless it's used somewhere else).
Data class:
class Data {
static int counter = 0;
boolean trueOrFalse;
String string;
public Data() {
counter++;
}
public Data(boolean someBoolean, String someString) {
this.trueOrFalse= someBoolean;
this.string = someString;
counter++;
}
}
setData()-Method:
public List<ProcessData> setData() {
List<ProcessData> processedDataList = new ArrayList<ProcessData>();
for (int i = 0; i < someCounterHere; i++) {
processedDataList.add(new ProcessData(new Data(true, "testString"));
// a new Data-object is created (parameters true and "testString")
// a new ProcessData-object is created (parameter is the newly created Data-Object)
// the newly created ProcessData-object is added to the list
}
return processedDataList;
}
ProcessData-class:
private class ProcessData {
private final Map<String, List<?>> map = new HashMap<String, List<?>>();
int counter;
public ProcessData(Data data) {
map.put("trueOrFalse", data.trueOrFalse);
map.put("string", data.string);
counter = data.counter;
}
public String someMethodToGenerateReturnData() {
// some code here to make use of the Data collected. Will basically use map to construct the return String
}
}
I am having issues with objects and classes.
I had to define two classes:
Course: a course has a code, an name and a number of credits
Teacher: a teacher has a first name and last name. He can be asked his full name.
So far so good, I got no issue with them, but I have to do next assignment which I was trying to do in the last 2 days and I could not find a proper answer:
Extend the code of the class teacher. A teacher also has a list of courses he can teach. Add an array of Courses to the code. Also add a function addCourse(Course aCourse) to the code. Courses can also be removed from teachers.
I could do everyting in my way but no clue on how to create the addCourse(Course aCourse) method.
Find below my coding, but it must be according to the method described:
public class Course {
private String courseCode;
private String courseName;
private String numberOfCredits;
public Course(String courseCode, String courseName, String numberOfCredits) {
super();
this.courseCode = courseCode;
this.courseName = courseName;
this.numberOfCredits = numberOfCredits;
}
public void print() {
System.out.println(courseCode + "\t" + courseName + "\t" + numberOfCredits);
}
public static void main(String[] args) {
Course[] courseArray = new Course[4];
System.out.println("Code" + "\t" + "Name" + "\t" + "Credits");
courseArray[0] = new Course("001", "Hist", "3");
courseArray[1] = new Course("002", "Phy", "3");
courseArray[2] = new Course("003", "Math", "3");
courseArray[3] = new Course("004", "Log", "3");
for (int i = 0; i < courseArray.length; i++) {
courseArray[i].print();
}
}
}
Arrays are fixed length collections of objects, so you'll need to decide how big your array should be. Let's call the length of your array MAX_COURSES. A more advanced solution might resize the array when required, but I get the impression this is beyond the scope of your course.
So you need to define the Course[] array as a field of your Teacher class. The syntax of array declarations is quite easy to research, so I won't put that in here. Just make sure your array length is equal to MAX_COURSES.
Now, to add courses to the array, you need to know where to put them. To keep track of the next free position of the array, the easiest thing to do is to declare a field in your class:
private int numCourses = 0;
Now, when you add a new course, insert the course into the index specified by numCourses. Make sure you increment numCourses after you've added the course.
Finally, you ought to test to see if your array is full before you agree to insert a new course into the array, i.e. check if numCourses is smaller than MAX_COURSES. If it's not, you need to throw an exception.
I would recommend using a collection (such as a List) rather than an array. The code would look something like:
public class Teacher {
private final String firstName;
private final String lastName;
private final List<Course> courses = new ArrayList<Course>();
public Teacher(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void addCourse(Course course) {
courses.add(course);
}
}
Based on that example, you should be able to add the removeCourse method yourself, and any other method you need to operate on the list of courses.
If you want to return the list as an array, you could always convert it, e.g:
public Course[] getCourses() {
return courses.toArray(new Course[courses.size()]);
}
If you really need to use an array for the data structure based on your assignment, something you can try when adding and removing courses, is to construct a list from the array of courses, add or remove a course from that list, the convert the list back to an array of courses.
There's really 3 options here.
Option 1
If you're allowed to use List constructs:
private List<Course> courses = new ArrayList<Course>();
public void addCourse(Course aCourse)
{
if (aCourse == null)
{
return;
}
courses.add(aCourse);
}
Option 2
The uses arrays, but it doesn't scale. Assume that a teacher can only have a maximum of X courses, in my example 10:
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
return;
}
courses[numCourses] = aCourse;
numCourses++;
}
Option 3
This is identical to the previous item, but is a bit smarter in that it can resize the array... by creating a new one using the static method Arrays.copyOf
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
int size = courses.length * 2;
courses = Arrays.copyOf(courses, size);
}
courses[numCourses] = aCourse;
numCourses++;
}
I don't think i have the terminology correct, haven't been one for that. What i'm trying to do is get a string back , then use it to run functions. .. Example :
int slotNumber = ((j*3)+i+1);
String slotString = "slot"+slotNumber;
Regularly I can do this :
slot12.Draw();
And I want to be able to do this :
slotString.Draw();
With it substituting slotString with slot12 in a dynamic scenario. If i truly have to i could do something similar to :
if (slotString == slot1) slot1.Draw();
if (slotString == slot2) slot2.Draw();
And such, but i dont really want to use x number of lines for x number of slots.
Any help is appreciated :D
A possible solution would be to use a HashMap where the key is the slotNumber and the value points to the slot. Then you could do something like the following.
//Initialize at the start of your program
HashMap<int, Slot> SlotHash = new HashMap<int, Slot>();
//Code to retrieve slot and call Draw().
Slot select = SlotHash.get(slotNumber);
select.Draw();
Maybe use a Map if your slots are sparsely-packed. If they're densely-packed, you might be able to use an array of slots. In either case, you do the slot lookup based on index and then call Draw on the looked-up slot.
You would have something like this:
Slot slot1 = new Slot("slot1");
Slot slot2 = new Slot("slot2");
SlotController controller = new SlotController();
controller.add(slot1);controller.add(slot2);
String someSlotNumber = ".....";
controller.draw(someSlotNumber);
See the definition of the classes below:
class SlotController {
Map<String, Slot> slotMap = new HashMap<String, Slot>();
public void addSlot(Slot aSlot) {
slotMap.put(aSlot.getSlotName(), aSlot);
}
public void draw(String slotName) {
slotMap.get(slotName).draw();
}
}
class Slot {
private String slotName;
public Slot(String name){
slotName = name;
}
public String getSlotName() {
return slotName;
}
public void draw() {
}
}